mirror of
https://github.com/h44z/wg-portal.git
synced 2025-10-05 16:06:17 +00:00
Compare commits
1 Commits
v2.1.0-rc.
...
enhance_pr
Author | SHA1 | Date | |
---|---|---|---|
|
4104fcc1d6 |
2
.github/workflows/chart.yml
vendored
2
.github/workflows/chart.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
# ct lint requires Python 3.x to run following packages:
|
||||
# - yamale (https://github.com/23andMe/Yamale)
|
||||
# - yamllint (https://github.com/adrienverge/yamllint)
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
|
2
.github/workflows/pages.yml
vendored
2
.github/workflows/pages.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
|
@@ -20,7 +20,7 @@ RUN npm run build
|
||||
######
|
||||
# Build backend
|
||||
######
|
||||
FROM --platform=${BUILDPLATFORM} golang:1.25-alpine AS builder
|
||||
FROM --platform=${BUILDPLATFORM} golang:1.24-alpine AS builder
|
||||
# Set the working directory
|
||||
WORKDIR /build
|
||||
# Download dependencies
|
||||
|
@@ -11,24 +11,6 @@ core:
|
||||
create_default_peer: true
|
||||
self_provisioning_allowed: true
|
||||
|
||||
backend:
|
||||
# default backend decides where new interfaces are created
|
||||
default: mikrotik
|
||||
|
||||
mikrotik:
|
||||
- id: mikrotik # unique id, not "local"
|
||||
display_name: RouterOS RB5009 # optional nice name
|
||||
api_url: https://10.10.10.10/rest
|
||||
api_user: wgportal
|
||||
api_password: a-super-secret-password
|
||||
api_verify_tls: false # set to false only if using self-signed during testing
|
||||
api_timeout: 30s # maximum request duration
|
||||
concurrency: 5 # limit parallel REST calls to device
|
||||
debug: false # verbose logging for this backend
|
||||
ignored_interfaces: # ignore these interfaces during import
|
||||
- wgTest1
|
||||
- wgTest2
|
||||
|
||||
web:
|
||||
site_title: My WireGuard Server
|
||||
site_company_name: My Company
|
||||
@@ -213,5 +195,3 @@ auth:
|
||||
registration_enabled: true
|
||||
log_user_info: true
|
||||
```
|
||||
|
||||
For more information, check out the usage documentation (e.g. [General Configuration](../usage/general.md) or [Backends Configuration](../usage/backends.md)).
|
||||
|
@@ -16,7 +16,6 @@ core:
|
||||
admin_user: admin@wgportal.local
|
||||
admin_password: wgportal-default
|
||||
admin_api_token: ""
|
||||
disable_admin_user: false
|
||||
editable_keys: true
|
||||
create_default_peer: false
|
||||
create_default_peer_on_creation: false
|
||||
@@ -132,10 +131,6 @@ More advanced options are found in the subsequent `Advanced` section.
|
||||
- **Description:** The administrator password. The default password should be changed immediately!
|
||||
- **Important:** The password should be strong and secure. The minimum password length is specified in [auth.min_password_length](#min_password_length). By default, it is 16 characters.
|
||||
|
||||
### `disable_admin_user`
|
||||
- **Default:** `false`
|
||||
- **Description:** If `true`, no admin user is created. This is useful if you plan to manage users exclusively through external authentication providers such as LDAP or OAuth.
|
||||
|
||||
### `admin_api_token`
|
||||
- **Default:** *(empty)*
|
||||
- **Description:** An API token for the admin user. If a token is provided, the REST API can be accessed using this token. If empty, the API is initially disabled for the admin user.
|
||||
@@ -184,11 +179,6 @@ The current MikroTik backend is in **BETA** and may not support all features.
|
||||
- **Description:** The default backend to use for managing WireGuard interfaces.
|
||||
Valid options are: `local`, or other backend id's configured in the `mikrotik` section.
|
||||
|
||||
### `ignored_local_interfaces`
|
||||
- **Default:** *(empty)*
|
||||
- **Description:** A list of interface names to exclude when enumerating local interfaces.
|
||||
This is useful if you want to prevent certain interfaces from being imported from the local system.
|
||||
|
||||
### Mikrotik
|
||||
|
||||
The `mikrotik` array contains a list of MikroTik backend definitions. Each entry describes how to connect to a MikroTik RouterOS instance that hosts WireGuard interfaces.
|
||||
@@ -230,11 +220,6 @@ Below are the properties for each entry inside `backend.mikrotik`:
|
||||
- **Default:** `5`
|
||||
- **Description:** Maximum number of concurrent API requests the backend will issue when enumerating interfaces and their details. If `0` or negative, a sane default of `5` is used.
|
||||
|
||||
#### `ignored_interfaces`
|
||||
- **Default:** *(empty)*
|
||||
- **Description:** A list of interface names to exclude during interface enumeration.
|
||||
This is useful if you want to prevent specific interfaces from being imported from the MikroTik device.
|
||||
|
||||
#### `debug`
|
||||
- **Default:** `false`
|
||||
- **Description:** Enable verbose debug logging for the MikroTik backend.
|
||||
|
@@ -63,7 +63,6 @@ const languageFlag = computed(() => {
|
||||
uk: "ua",
|
||||
zh: "cn",
|
||||
ko: "kr",
|
||||
es: "es",
|
||||
|
||||
};
|
||||
return "fi-" + (langMap[lang] || lang);
|
||||
@@ -183,7 +182,6 @@ const userDisplayName = computed(() => {
|
||||
<a class="dropdown-item" href="#" @click.prevent="switchLanguage('uk')"><span class="fi fi-ua"></span> Українська</a>
|
||||
<a class="dropdown-item" href="#" @click.prevent="switchLanguage('vi')"><span class="fi fi-vi"></span> Tiếng Việt</a>
|
||||
<a class="dropdown-item" href="#" @click.prevent="switchLanguage('zh')"><span class="fi fi-cn"></span> 中文</a>
|
||||
<a class="dropdown-item" href="#" @click.prevent="switchLanguage('es')"><span class="fi fi-es"></span> Español</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -53,7 +53,6 @@ export function freshPeer() {
|
||||
Identifier: "",
|
||||
DisplayName: "",
|
||||
UserIdentifier: "",
|
||||
UserDisplayName: "",
|
||||
InterfaceIdentifier: "",
|
||||
Disabled: false,
|
||||
ExpiresAt: null,
|
||||
|
@@ -8,7 +8,6 @@ import ru from './translations/ru.json';
|
||||
import uk from './translations/uk.json';
|
||||
import vi from './translations/vi.json';
|
||||
import zh from './translations/zh.json';
|
||||
import es from './translations/es.json';
|
||||
|
||||
import {createI18n} from "vue-i18n";
|
||||
|
||||
@@ -33,7 +32,6 @@ const i18n = createI18n({
|
||||
"uk": uk,
|
||||
"vi": vi,
|
||||
"zh": zh,
|
||||
"es": es,
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -1,587 +0,0 @@
|
||||
{
|
||||
"languages": {
|
||||
"es": "Español"
|
||||
},
|
||||
"general": {
|
||||
"pagination": {
|
||||
"size": "Numero de elementos",
|
||||
"all": "Todos (Lento)"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Buscar...",
|
||||
"button": "Buscar"
|
||||
},
|
||||
"select-all": "Buscar todos",
|
||||
"yes": "Sí",
|
||||
"no": "No",
|
||||
"cancel": "Cancelar",
|
||||
"close": "Cerrar",
|
||||
"save": "Guardar",
|
||||
"delete": "Eliminar"
|
||||
},
|
||||
"login": {
|
||||
"headline": "Por favor inicie sesión",
|
||||
"username": {
|
||||
"label": "Usuario",
|
||||
"placeholder": "Por favor ingrese su usuario"
|
||||
},
|
||||
"password": {
|
||||
"label": "Contraseña",
|
||||
"placeholder": "Por favor ingrese su contraseña"
|
||||
},
|
||||
"button": "Ingresar",
|
||||
"button-webauthn": "Usar clave de acceso"
|
||||
},
|
||||
"menu": {
|
||||
"home": "Inicio",
|
||||
"interfaces": "Interfaces",
|
||||
"users": "Usuarios",
|
||||
"lang": "Cambiar idioma",
|
||||
"profile": "Mi perfil",
|
||||
"settings": "Configuración",
|
||||
"audit": "Registro de auditoría",
|
||||
"login": "Iniciar sesión",
|
||||
"logout": "Cerrar sesión",
|
||||
"keygen": "Generador de claves"
|
||||
},
|
||||
"home": {
|
||||
"headline": "Portal VPN WireGuard®",
|
||||
"info-headline": "Más información",
|
||||
"abstract": "WireGuard® es una VPN extremadamente simple pero rápida y moderna que utiliza criptografía de última generación. Su objetivo es ser más rápida, simple, ligera y útil que IPsec, a la vez que evita los enormes problemas que supone. Su objetivo es ofrecer un rendimiento considerablemente superior al de OpenVPN.",
|
||||
"installation": {
|
||||
"box-header": "Instalación de WireGuard",
|
||||
"headline": "Instalación",
|
||||
"content": "Las instrucciones de instalación del cliente se pueden encontrar en el sitio web oficial de WireGuard.",
|
||||
"button": "Abrir instrucciones"
|
||||
},
|
||||
"about-wg": {
|
||||
"box-header": "Acerca de WireGuard",
|
||||
"headline": "Acerca de",
|
||||
"content": "WireGuard® es una VPN extremadamente simple pero rápida y moderna que utiliza criptografía de última generación.",
|
||||
"button": "Más"
|
||||
},
|
||||
"about-portal": {
|
||||
"box-header": "Acerca del Portal WireGuard",
|
||||
"headline": "Portal WireGuard",
|
||||
"content": "WireGuard Portal es un portal web simple para la configuración de WireGuard.",
|
||||
"button": "Más"
|
||||
},
|
||||
"profiles": {
|
||||
"headline": "Perfiles VPN",
|
||||
"abstract": "Puedes acceder y descargar tus configuraciones personales de VPN desde tu perfil de usuario.",
|
||||
"content": "para ver todos tus perfiles configurados, haz clic en el botón de abajo.",
|
||||
"button": "Abrir mi perfil"
|
||||
},
|
||||
"admin": {
|
||||
"headline": "Área de administración",
|
||||
"abstract": "En el área de administración puedes gestionar los peers de WireGuard, la interfaz del servidor, así como los usuarios que tienen acceso al Portal WireGuard.",
|
||||
"content": "",
|
||||
"button-admin": "Abrir administración del servidor",
|
||||
"button-user": "Abrir administración de usuarios"
|
||||
}
|
||||
},
|
||||
"interfaces": {
|
||||
"headline": "Administración de interfaces",
|
||||
"headline-peers": "Peers VPN actuales",
|
||||
"headline-endpoints": "Extremos actuales",
|
||||
"no-interface": {
|
||||
"default-selection": "No hay interfaces disponibles",
|
||||
"headline": "No se encontraron interfaces...",
|
||||
"abstract": "Haz clic en el botón + para crear una nueva interfaz WireGuard."
|
||||
},
|
||||
"no-peer": {
|
||||
"headline": "No hay peers disponibles",
|
||||
"abstract": "Actualmente no hay peers disponibles para la interfaz WireGuard seleccionada."
|
||||
},
|
||||
"table-heading": {
|
||||
"name": "Nombre",
|
||||
"user": "Usuario",
|
||||
"ip": "IP's",
|
||||
"endpoint": "Endpoint",
|
||||
"status": "Estado"
|
||||
},
|
||||
"interface": {
|
||||
"headline": "Estado de la interfaz para",
|
||||
"backend": "Backend",
|
||||
"unknown-backend": "Desconocido",
|
||||
"wrong-backend": "Backend inválido, usando backend local de WireGuard en su lugar.",
|
||||
"key": "Clave pública",
|
||||
"endpoint": "Endpoint público",
|
||||
"port": "Puerto de escucha",
|
||||
"peers": "Peers habilitados",
|
||||
"total-peers": "Peers totales",
|
||||
"endpoints": "Endpoints habilitados",
|
||||
"total-endpoints": "Endpoints totales",
|
||||
"ip": "Dirección IP",
|
||||
"default-allowed-ip": "IPs permitidas por defecto",
|
||||
"dns": "Servidores DNS",
|
||||
"mtu": "MTU",
|
||||
"default-keep-alive": "Intervalo Keepalive por defecto",
|
||||
"button-show-config": "Mostrar configuración",
|
||||
"button-download-config": "Descargar configuración",
|
||||
"button-store-config": "Guardar configuración para wg-quick",
|
||||
"button-edit": "Editar interfaz"
|
||||
},
|
||||
"button-add-interface": "Agregar interfaz",
|
||||
"button-add-peer": "Agregar peer",
|
||||
"button-add-peers": "Agregar múltiples peers",
|
||||
"button-show-peer": "Mostrar peer",
|
||||
"button-edit-peer": "Editar peer",
|
||||
"peer-disabled": "Peer deshabilitado, motivo:",
|
||||
"peer-expiring": "El peer expira en",
|
||||
"peer-connected": "Conectado",
|
||||
"peer-not-connected": "No conectado",
|
||||
"peer-handshake": "Último handshake:"
|
||||
},
|
||||
"users": {
|
||||
"headline": "Administración de usuarios",
|
||||
"table-heading": {
|
||||
"id": "ID",
|
||||
"email": "Correo electrónico",
|
||||
"firstname": "Nombre",
|
||||
"lastname": "Apellido",
|
||||
"source": "Origen",
|
||||
"peers": "Peers",
|
||||
"admin": "Administrador"
|
||||
},
|
||||
"no-user": {
|
||||
"headline": "No hay usuarios disponibles",
|
||||
"abstract": "Actualmente no hay usuarios registrados en el Portal WireGuard."
|
||||
},
|
||||
"button-add-user": "Agregar usuario",
|
||||
"button-show-user": "Mostrar usuario",
|
||||
"button-edit-user": "Editar usuario",
|
||||
"user-disabled": "Usuario deshabilitado, motivo:",
|
||||
"user-locked": "Cuenta bloqueada, motivo:",
|
||||
"admin": "El usuario tiene privilegios de administrador",
|
||||
"no-admin": "El usuario no tiene privilegios de administrador"
|
||||
},
|
||||
"profile": {
|
||||
"headline": "Mis peers VPN",
|
||||
"table-heading": {
|
||||
"name": "Nombre",
|
||||
"ip": "IP's",
|
||||
"stats": "Estado",
|
||||
"interface": "Interfaz del servidor"
|
||||
},
|
||||
"no-peer": {
|
||||
"headline": "No hay peers disponibles",
|
||||
"abstract": "Actualmente no hay peers asociados a tu perfil de usuario."
|
||||
},
|
||||
"peer-connected": "Conectado",
|
||||
"button-add-peer": "Agregar peer",
|
||||
"button-show-peer": "Mostrar peer",
|
||||
"button-edit-peer": "Editar peer"
|
||||
},
|
||||
"settings": {
|
||||
"headline": "Configuración",
|
||||
"abstract": "Aquí puedes cambiar tu configuración personal.",
|
||||
"api": {
|
||||
"headline": "Configuración de API",
|
||||
"abstract": "Aquí puedes configurar los ajustes de la API RESTful.",
|
||||
"active-description": "La API está actualmente activa para tu cuenta. Todas las solicitudes están autenticadas con Basic Auth. Usa las siguientes credenciales.",
|
||||
"inactive-description": "La API está actualmente inactiva. Presiona el botón de abajo para activarla.",
|
||||
"user-label": "Usuario de la API:",
|
||||
"user-placeholder": "Usuario de la API",
|
||||
"token-label": "Contraseña de la API:",
|
||||
"token-placeholder": "Token de la API",
|
||||
"token-created-label": "Acceso API concedido en: ",
|
||||
"button-disable-title": "Desactivar API, invalidará el token actual.",
|
||||
"button-disable-text": "Desactivar API",
|
||||
"button-enable-title": "Activar API, generará un nuevo token.",
|
||||
"button-enable-text": "Activar API",
|
||||
"api-link": "Documentación de API"
|
||||
},
|
||||
"webauthn": {
|
||||
"headline": "Configuración de llave de acceso",
|
||||
"abstract": "Las llaves de acceso son una forma moderna de autenticar usuarios sin necesidad de contraseñas. Se almacenan de forma segura en tu navegador y pueden usarse para iniciar sesión en el Portal WireGuard.",
|
||||
"active-description": "Al menos una llave de acceso está activa en tu cuenta.",
|
||||
"inactive-description": "Actualmente no hay llaves de acceso registradas. Presiona el botón de abajo para registrar una.",
|
||||
"table": {
|
||||
"name": "Nombre",
|
||||
"created": "Creada",
|
||||
"actions": ""
|
||||
},
|
||||
"credentials-list": "Llaves de acceso registradas actualmente",
|
||||
"modal-delete": {
|
||||
"headline": "Eliminar llaves de acceso",
|
||||
"abstract": "¿Seguro que deseas eliminar esta llave de acceso? Ya no podrás usarla para iniciar sesión.",
|
||||
"created": "Creada:",
|
||||
"button-delete": "Eliminar",
|
||||
"button-cancel": "Cancelar"
|
||||
},
|
||||
"button-rename-title": "Renombrar",
|
||||
"button-rename-text": "Renombrar la llave de acceso.",
|
||||
"button-save-title": "Guardar",
|
||||
"button-save-text": "Guardar el nuevo nombre de la llave de acceso.",
|
||||
"button-cancel-title": "Cancelar",
|
||||
"button-cancel-text": "Cancelar el renombrado de la llave de acceso.",
|
||||
"button-delete-title": "Eliminar",
|
||||
"button-delete-text": "Eliminar la llave de acceso. Ya no podrás iniciar sesión con ella.",
|
||||
"button-register-title": "Registrar llave de acceso",
|
||||
"button-register-text": "Registrar una nueva llave de acceso para proteger tu cuenta."
|
||||
}
|
||||
},
|
||||
"audit": {
|
||||
"headline": "Registro de Auditoría",
|
||||
"abstract": "Aquí puedes encontrar el registro de auditoría de todas las acciones realizadas en el Portal WireGuard.",
|
||||
"no-entries": {
|
||||
"headline": "No hay entradas en el registro",
|
||||
"abstract": "Actualmente no se han registrado auditorías."
|
||||
},
|
||||
"entries-headline": "Entradas del Registro",
|
||||
"table-heading": {
|
||||
"id": "#",
|
||||
"time": "Hora",
|
||||
"user": "Usuario",
|
||||
"severity": "Severidad",
|
||||
"origin": "Origen",
|
||||
"message": "Mensaje"
|
||||
}
|
||||
},
|
||||
"keygen": {
|
||||
"headline": "Generador de claves WireGuard",
|
||||
"abstract": "Genera nuevas claves de WireGuard. Las claves se generan en tu navegador local y nunca se envían al servidor.",
|
||||
"headline-keypair": "Nuevo par de claves",
|
||||
"headline-preshared-key": "Nueva clave pre-compartida",
|
||||
"button-generate": "Generar",
|
||||
"private-key": {
|
||||
"label": "Clave privada",
|
||||
"placeholder": "La clave privada"
|
||||
},
|
||||
"public-key": {
|
||||
"label": "Clave pública",
|
||||
"placeholder": "La clave pública"
|
||||
},
|
||||
"preshared-key": {
|
||||
"label": "Clave pre-compartida",
|
||||
"placeholder": "La clave pre-compartida"
|
||||
}
|
||||
},
|
||||
"modals": {
|
||||
"user-view": {
|
||||
"headline": "Cuenta de Usuario:",
|
||||
"tab-user": "Información",
|
||||
"tab-peers": "Peers",
|
||||
"headline-info": "Información del Usuario:",
|
||||
"headline-notes": "Notas:",
|
||||
"email": "Correo Electrónico",
|
||||
"firstname": "Nombre",
|
||||
"lastname": "Apellido",
|
||||
"phone": "Número de Teléfono",
|
||||
"depeertment": "Departamento",
|
||||
"api-enabled": "Acceso API",
|
||||
"disabled": "Cuenta Deshabilitada",
|
||||
"locked": "Cuenta Bloqueada",
|
||||
"no-peers": "El usuario no tiene peers asociados.",
|
||||
"peers": {
|
||||
"name": "Nombre",
|
||||
"interface": "Interfaz",
|
||||
"ip": "IP's"
|
||||
}
|
||||
},
|
||||
"user-edit": {
|
||||
"headline-edit": "Editar usuario:",
|
||||
"headline-new": "Nuevo usuario",
|
||||
"header-general": "General",
|
||||
"header-personal": "Información del Usuario",
|
||||
"header-notes": "Notas",
|
||||
"header-state": "Estado",
|
||||
"identifier": {
|
||||
"label": "Identificador",
|
||||
"placeholder": "El identificador único del usuario"
|
||||
},
|
||||
"source": {
|
||||
"label": "Origen",
|
||||
"placeholder": "El origen del usuario"
|
||||
},
|
||||
"password": {
|
||||
"label": "Contraseña",
|
||||
"placeholder": "Una contraseña súper segura",
|
||||
"description": "Deja este campo en blanco para mantener la contraseña actual.",
|
||||
"too-weak": "La contraseña es demasiado débil. Por favor usa una más fuerte."
|
||||
},
|
||||
"email": {
|
||||
"label": "Correo",
|
||||
"placeholder": "La dirección de correo"
|
||||
},
|
||||
"phone": {
|
||||
"label": "Teléfono",
|
||||
"placeholder": "El número de teléfono"
|
||||
},
|
||||
"depeertment": {
|
||||
"label": "Departamento",
|
||||
"placeholder": "El departamento"
|
||||
},
|
||||
"firstname": {
|
||||
"label": "Nombre",
|
||||
"placeholder": "Nombre"
|
||||
},
|
||||
"lastname": {
|
||||
"label": "Apellido",
|
||||
"placeholder": "Apellido"
|
||||
},
|
||||
"notes": {
|
||||
"label": "Notas",
|
||||
"placeholder": ""
|
||||
},
|
||||
"disabled": {
|
||||
"label": "Deshabilitado (sin conexión WireGuard y sin posibilidad de inicio de sesión)"
|
||||
},
|
||||
"locked": {
|
||||
"label": "Bloqueado (no es posible iniciar sesión, las conexiones WireGuard aún funcionan)"
|
||||
},
|
||||
"admin": {
|
||||
"label": "Es administrador"
|
||||
}
|
||||
},
|
||||
"interface-view": {
|
||||
"headline": "Configuración de la interfaz:"
|
||||
},
|
||||
"interface-edit": {
|
||||
"headline-edit": "Editar interfaz:",
|
||||
"headline-new": "Nueva interfaz",
|
||||
"tab-interface": "Interfaz",
|
||||
"tab-peerdef": "Valores predeterminados del peer",
|
||||
"header-general": "General",
|
||||
"header-network": "Red",
|
||||
"header-crypto": "Criptografía",
|
||||
"header-hooks": "Hooks de interfaz",
|
||||
"header-peer-hooks": "Hooks",
|
||||
"header-state": "Estado",
|
||||
"identifier": {
|
||||
"label": "Identificador",
|
||||
"placeholder": "El identificador único de la interfaz"
|
||||
},
|
||||
"mode": {
|
||||
"label": "Modo de Interfaz",
|
||||
"server": "Modo Servidor",
|
||||
"client": "Modo Cliente",
|
||||
"any": "Modo Desconocido"
|
||||
},
|
||||
"backend": {
|
||||
"label": "Backend de la Interfaz",
|
||||
"invalid-label": "El backend original ya no está disponible, usando el backend local de WireGuard en su lugar.",
|
||||
"local": "Backend local de WireGuard"
|
||||
},
|
||||
"display-name": {
|
||||
"label": "Nombre para Mostrar",
|
||||
"placeholder": "El nombre descriptivo de la interfaz"
|
||||
},
|
||||
"private-key": {
|
||||
"label": "La clave Privada",
|
||||
"placeholder": "La clave privada"
|
||||
},
|
||||
"public-key": {
|
||||
"label": "La clave pública",
|
||||
"placeholder": "La clave pública"
|
||||
},
|
||||
"ip": {
|
||||
"label": "Direcciones IP",
|
||||
"placeholder": "Direcciones IP (formato CIDR)"
|
||||
},
|
||||
"listen-port": {
|
||||
"label": "Puerto de Escucha",
|
||||
"placeholder": "El puerto de escucha"
|
||||
},
|
||||
"dns": {
|
||||
"label": "Servidor DNS",
|
||||
"placeholder": "Los servidores DNS que deben usarse"
|
||||
},
|
||||
"dns-search": {
|
||||
"label": "Dominios de Búsqueda DNS",
|
||||
"placeholder": "Prefijos de búsqueda DNS"
|
||||
},
|
||||
"mtu": {
|
||||
"label": "MTU",
|
||||
"placeholder": "La MTU de la interfaz (0 = mantener por defecto)"
|
||||
},
|
||||
"firewall-mark": {
|
||||
"label": "Marca de Firewall",
|
||||
"placeholder": "Marca de firewall que se aplica al tráfico saliente. (0 = automático)"
|
||||
},
|
||||
"routing-table": {
|
||||
"label": "Tabla de Enrutamiento",
|
||||
"placeholder": "El ID de la tabla de enrutamiento",
|
||||
"description": "Casos especiales: off = no administrar rutas, 0 = automático"
|
||||
},
|
||||
"pre-up": {
|
||||
"label": "Pre-Up",
|
||||
"placeholder": "Uno o varios comandos bash separados por ;"
|
||||
},
|
||||
"post-up": {
|
||||
"label": "Post-Up",
|
||||
"placeholder": "Uno o varios comandos bash separados por ;"
|
||||
},
|
||||
"pre-down": {
|
||||
"label": "Pre-Down",
|
||||
"placeholder": "Uno o varios comandos bash separados por ;"
|
||||
},
|
||||
"post-down": {
|
||||
"label": "Post-Down",
|
||||
"placeholder": "Uno o varios comandos bash separados por ;"
|
||||
},
|
||||
"disabled": {
|
||||
"label": "Interfaz Deshabilitada"
|
||||
},
|
||||
"save-config": {
|
||||
"label": "Guardar automáticamente la configuración de wg-quick"
|
||||
},
|
||||
"defaults": {
|
||||
"endpoint": {
|
||||
"label": "Dirección del Endpoint",
|
||||
"placeholder": "Dirección del Endpoint",
|
||||
"description": "La dirección del endpoint al que los peers se conectarán. (ej: wg.ejemplo.com o wg.ejemplo.com:51820)"
|
||||
},
|
||||
"networks": {
|
||||
"label": "Redes IP",
|
||||
"placeholder": "Direcciones de Red",
|
||||
"description": "Los peers obtendrán direcciones IP de esas subredes."
|
||||
},
|
||||
"allowed-ip": {
|
||||
"label": "Direcciones IP Permitidas",
|
||||
"placeholder": "Direcciones IP Permitidas por Defecto"
|
||||
},
|
||||
"mtu": {
|
||||
"label": "MTU",
|
||||
"placeholder": "La MTU del cliente (0 = mantener por defecto)"
|
||||
},
|
||||
"keep-alive": {
|
||||
"label": "Intervalo de Keep Alive",
|
||||
"placeholder": "Keepalive Persistente (0 = por defecto)"
|
||||
}
|
||||
},
|
||||
"button-apply-defaults": "Aplicar Valores Predeterminados de peers"
|
||||
},
|
||||
"peer-view": {
|
||||
"headline-peer": "Peer:",
|
||||
"headline-endpoint": "Endpoint:",
|
||||
"section-info": "Información del peer",
|
||||
"section-status": "Estado Actual",
|
||||
"section-config": "Configuración",
|
||||
"identifier": "Identificador",
|
||||
"ip": "Direcciones IP",
|
||||
"user": "Usuario Asociado",
|
||||
"notes": "Notas",
|
||||
"expiry-status": "Expira en",
|
||||
"disabled-status": "Deshabilitado en",
|
||||
"traffic": "Tráfico",
|
||||
"connection-status": "Estadísticas de Conexión",
|
||||
"upload": "Bytes Subidos (del Servidor al peer)",
|
||||
"download": "Bytes Descargados (del peer al Servidor)",
|
||||
"pingable": "Es Alcanzable (Ping)",
|
||||
"handshake": "Último Handshake",
|
||||
"connected-since": "Conectado desde",
|
||||
"endpoint": "Endpoint",
|
||||
"button-download": "Descargar configuración",
|
||||
"button-email": "Enviar configuración por Correo Electrónico",
|
||||
"style-label": "Estilo de Configuración"
|
||||
},
|
||||
"peer-edit": {
|
||||
"headline-edit-peer": "Editar peer:",
|
||||
"headline-edit-endpoint": "Editar endpoint:",
|
||||
"headline-new-peer": "Crear peer",
|
||||
"headline-new-endpoint": "Crear endpoint",
|
||||
"header-general": "General",
|
||||
"header-network": "Red",
|
||||
"header-crypto": "Criptografía",
|
||||
"header-hooks": "Hooks (Ejecutados en el peer)",
|
||||
"header-state": "Estado",
|
||||
"display-name": {
|
||||
"label": "Nombre para Mostrar",
|
||||
"placeholder": "El nombre descriptivo para el peer"
|
||||
},
|
||||
"linked-user": {
|
||||
"label": "Usuario Vinculado",
|
||||
"placeholder": "La cuenta de usuario que posee este peer"
|
||||
},
|
||||
"private-key": {
|
||||
"label": "Clave Privada",
|
||||
"placeholder": "Clave privada",
|
||||
"help": "La clave privada se almacena de forma segura en el servidor. Si el usuario ya posee una copia, puedes omitir este campo. El servidor sigue funcionando exclusivamente con la clave pública del peer."
|
||||
},
|
||||
"public-key": {
|
||||
"label": "Cave Pública",
|
||||
"placeholder": "La Clave pública"
|
||||
},
|
||||
"preshared-key": {
|
||||
"label": "Clave pre-compartida",
|
||||
"placeholder": "Clave pre-compartida opcional"
|
||||
},
|
||||
"endpoint": {
|
||||
"label": "Dirección del endpoint",
|
||||
"placeholder": "La dirección del endpoint remoto"
|
||||
},
|
||||
"ip": {
|
||||
"label": "Direcciones IP",
|
||||
"placeholder": "Direcciones IP (formato CIDR)"
|
||||
},
|
||||
"allowed-ip": {
|
||||
"label": "Direcciones IP permitidas",
|
||||
"placeholder": "Direcciones IP permitidas (formato CIDR)"
|
||||
},
|
||||
"extra-allowed-ip": {
|
||||
"label": "Direcciones IP permitidas extra",
|
||||
"placeholder": "IPs extra permitidas (lado del servidor)",
|
||||
"description": "Esas IPs serán agregadas en la interfaz remota de WireGuard como direcciones IP permitidas."
|
||||
},
|
||||
"dns": {
|
||||
"label": "Servidor DNS",
|
||||
"placeholder": "Los servidores DNS que deben usarse"
|
||||
},
|
||||
"dns-search": {
|
||||
"label": "Dominios de búsqueda DNS",
|
||||
"placeholder": "Prefijos de búsqueda DNS"
|
||||
},
|
||||
"keep-alive": {
|
||||
"label": "Intervalo de Keep Alive",
|
||||
"placeholder": "Keepalive Persistente (0 = por defecto)"
|
||||
},
|
||||
"mtu": {
|
||||
"label": "MTU",
|
||||
"placeholder": "La MTU del cliente (0 = mantener por defecto)"
|
||||
},
|
||||
"pre-up": {
|
||||
"label": "Pre-Up",
|
||||
"placeholder": "Uno o varios comandos bash separados por ;"
|
||||
},
|
||||
"post-up": {
|
||||
"label": "Post-Up",
|
||||
"placeholder": "Uno o varios comandos bash separados por ;"
|
||||
},
|
||||
"pre-down": {
|
||||
"label": "Pre-Down",
|
||||
"placeholder": "Uno o varios comandos bash separados por ;"
|
||||
},
|
||||
"post-down": {
|
||||
"label": "Post-Down",
|
||||
"placeholder": "Uno o varios comandos bash separados por ;"
|
||||
},
|
||||
"disabled": {
|
||||
"label": "Peer Deshabilitado"
|
||||
},
|
||||
"ignore-global": {
|
||||
"label": "Ignorar configuración global"
|
||||
},
|
||||
"expires-at": {
|
||||
"label": "Fecha de expiración"
|
||||
}
|
||||
},
|
||||
"peer-multi-create": {
|
||||
"headline-peer": "Crear múltiples peers",
|
||||
"headline-endpoint": "Crear múltiples endpoints",
|
||||
"identifiers": {
|
||||
"label": "Identificadores de Usuario",
|
||||
"placeholder": "Identificadores de Usuario",
|
||||
"description": "Un identificador de usuario (el nombre de usuario) para el cual debe crearse un peer."
|
||||
},
|
||||
"prefix": {
|
||||
"headline-peer": "peer:",
|
||||
"headline-endpoint": "Endpoint:",
|
||||
"label": "Prefijo del Nombre peera Mostrar",
|
||||
"placeholder": "El prefijo",
|
||||
"description": "Un prefijo que se agregará al nombre mostrado de los peers."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -400,7 +400,7 @@ onMounted(async () => {
|
||||
<span v-if="!peer.Disabled && peer.ExpiresAt" class="text-warning" :title="$t('interfaces.peer-expiring') + ' ' + peer.ExpiresAt"><i class="fas fa-hourglass-end expiring-peer"></i></span>
|
||||
</td>
|
||||
<td><span v-if="peer.DisplayName" :title="peer.Identifier">{{peer.DisplayName}}</span><span v-else :title="peer.Identifier">{{ $filters.truncate(peer.Identifier, 10)}}</span></td>
|
||||
<td><span :title="peer.UserDisplayName">{{peer.UserIdentifier}}</span></td>
|
||||
<td>{{peer.UserIdentifier}}</td>
|
||||
<td>
|
||||
<span v-for="ip in peer.Addresses" :key="ip" class="badge bg-light me-1">{{ ip }}</span>
|
||||
</td>
|
||||
|
67
go.mod
67
go.mod
@@ -8,28 +8,28 @@ require (
|
||||
github.com/coreos/go-oidc/v3 v3.15.0
|
||||
github.com/glebarez/sqlite v1.11.0
|
||||
github.com/go-ldap/ldap/v3 v3.4.11
|
||||
github.com/go-pkgz/routegroup v1.5.3
|
||||
github.com/go-pkgz/routegroup v1.5.2
|
||||
github.com/go-playground/validator/v10 v10.27.0
|
||||
github.com/go-webauthn/webauthn v0.14.0
|
||||
github.com/go-webauthn/webauthn v0.13.4
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/prometheus-community/pro-bing v0.7.0
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/prometheus/client_golang v1.23.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/swaggo/swag v1.16.6
|
||||
github.com/vardius/message-bus v1.1.5
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
github.com/xhit/go-simple-mail/v2 v2.16.0
|
||||
github.com/yeqown/go-qrcode/v2 v2.2.5
|
||||
github.com/yeqown/go-qrcode/writer/compressed v1.0.1
|
||||
golang.org/x/crypto v0.42.0
|
||||
golang.org/x/oauth2 v0.31.0
|
||||
golang.org/x/sys v0.36.0
|
||||
golang.org/x/crypto v0.41.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gorm.io/driver/mysql v1.6.0
|
||||
gorm.io/driver/postgres v1.6.0
|
||||
gorm.io/driver/sqlserver v1.6.1
|
||||
gorm.io/gorm v1.31.0
|
||||
gorm.io/gorm v1.30.1
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -41,73 +41,62 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.22.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.2 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/spec v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.24.1 // indirect
|
||||
github.com/go-openapi/swag/cmdutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/conv v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/fileutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/jsonname v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/jsonutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/loading v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/mangling v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/netutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/stringutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/typeutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/yamlutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.1 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-sql-driver/mysql v1.9.3 // indirect
|
||||
github.com/go-test/deep v1.1.1 // indirect
|
||||
github.com/go-webauthn/x v0.1.25 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/go-webauthn/x v0.1.23 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-tpm v0.9.5 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.6 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.5 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mdlayher/genetlink v1.3.2 // indirect
|
||||
github.com/mdlayher/netlink v1.8.0 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/microsoft/go-mssqldb v1.9.3 // indirect
|
||||
github.com/microsoft/go-mssqldb v1.9.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.66.1 // indirect
|
||||
github.com/prometheus/procfs v0.17.0 // indirect
|
||||
github.com/prometheus/common v0.65.0 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/toorop/go-dkim v0.0.0-20250226130143-9025cce95817 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/yeqown/reedsolomon v1.0.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
|
||||
golang.org/x/mod v0.28.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250808145144-a408d31f581a // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
golang.org/x/tools v0.36.0 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
modernc.org/libc v1.66.8 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
modernc.org/libc v1.66.6 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.38.2 // indirect
|
||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
|
151
go.sum
151
go.sum
@@ -50,50 +50,28 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
|
||||
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
|
||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI=
|
||||
github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
|
||||
github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM=
|
||||
github.com/go-openapi/jsonpointer v0.22.0 h1:TmMhghgNef9YXxTu1tOopo+0BGEytxA+okbry0HjZsM=
|
||||
github.com/go-openapi/jsonpointer v0.22.0/go.mod h1:xt3jV88UtExdIkkL7NloURjRQjbeUgcxFblMjq2iaiU=
|
||||
github.com/go-openapi/jsonreference v0.21.1 h1:bSKrcl8819zKiOgxkbVNRUBIr6Wwj9KYrDbMjRs0cDA=
|
||||
github.com/go-openapi/jsonreference v0.21.1/go.mod h1:PWs8rO4xxTUqKGu+lEvvCxD5k2X7QYkKAepJyCmSTT8=
|
||||
github.com/go-openapi/jsonpointer v0.21.2 h1:AqQaNADVwq/VnkCmQg6ogE+M3FOsKTytwges0JdwVuA=
|
||||
github.com/go-openapi/jsonpointer v0.21.2/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||
github.com/go-openapi/swag v0.24.1 h1:DPdYTZKo6AQCRqzwr/kGkxJzHhpKxZ9i/oX0zag+MF8=
|
||||
github.com/go-openapi/swag v0.24.1/go.mod h1:sm8I3lCPlspsBBwUm1t5oZeWZS0s7m/A+Psg0ooRU0A=
|
||||
github.com/go-openapi/swag/cmdutils v0.24.0 h1:KlRCffHwXFI6E5MV9n8o8zBRElpY4uK4yWyAMWETo9I=
|
||||
github.com/go-openapi/swag/cmdutils v0.24.0/go.mod h1:uxib2FAeQMByyHomTlsP8h1TtPd54Msu2ZDU/H5Vuf8=
|
||||
github.com/go-openapi/swag/conv v0.24.0 h1:ejB9+7yogkWly6pnruRX45D1/6J+ZxRu92YFivx54ik=
|
||||
github.com/go-openapi/swag/conv v0.24.0/go.mod h1:jbn140mZd7EW2g8a8Y5bwm8/Wy1slLySQQ0ND6DPc2c=
|
||||
github.com/go-openapi/swag/fileutils v0.24.0 h1:U9pCpqp4RUytnD689Ek/N1d2N/a//XCeqoH508H5oak=
|
||||
github.com/go-openapi/swag/fileutils v0.24.0/go.mod h1:3SCrCSBHyP1/N+3oErQ1gP+OX1GV2QYFSnrTbzwli90=
|
||||
github.com/go-openapi/swag/jsonname v0.24.0 h1:2wKS9bgRV/xB8c62Qg16w4AUiIrqqiniJFtZGi3dg5k=
|
||||
github.com/go-openapi/swag/jsonname v0.24.0/go.mod h1:GXqrPzGJe611P7LG4QB9JKPtUZ7flE4DOVechNaDd7Q=
|
||||
github.com/go-openapi/swag/jsonutils v0.24.0 h1:F1vE1q4pg1xtO3HTyJYRmEuJ4jmIp2iZ30bzW5XgZts=
|
||||
github.com/go-openapi/swag/jsonutils v0.24.0/go.mod h1:vBowZtF5Z4DDApIoxcIVfR8v0l9oq5PpYRUuteVu6f0=
|
||||
github.com/go-openapi/swag/loading v0.24.0 h1:ln/fWTwJp2Zkj5DdaX4JPiddFC5CHQpvaBKycOlceYc=
|
||||
github.com/go-openapi/swag/loading v0.24.0/go.mod h1:gShCN4woKZYIxPxbfbyHgjXAhO61m88tmjy0lp/LkJk=
|
||||
github.com/go-openapi/swag/mangling v0.24.0 h1:PGOQpViCOUroIeak/Uj/sjGAq9LADS3mOyjznmHy2pk=
|
||||
github.com/go-openapi/swag/mangling v0.24.0/go.mod h1:Jm5Go9LHkycsz0wfoaBDkdc4CkpuSnIEf62brzyCbhc=
|
||||
github.com/go-openapi/swag/netutils v0.24.0 h1:Bz02HRjYv8046Ycg/w80q3g9QCWeIqTvlyOjQPDjD8w=
|
||||
github.com/go-openapi/swag/netutils v0.24.0/go.mod h1:WRgiHcYTnx+IqfMCtu0hy9oOaPR0HnPbmArSRN1SkZM=
|
||||
github.com/go-openapi/swag/stringutils v0.24.0 h1:i4Z/Jawf9EvXOLUbT97O0HbPUja18VdBxeadyAqS1FM=
|
||||
github.com/go-openapi/swag/stringutils v0.24.0/go.mod h1:5nUXB4xA0kw2df5PRipZDslPJgJut+NjL7D25zPZ/4w=
|
||||
github.com/go-openapi/swag/typeutils v0.24.0 h1:d3szEGzGDf4L2y1gYOSSLeK6h46F+zibnEas2Jm/wIw=
|
||||
github.com/go-openapi/swag/typeutils v0.24.0/go.mod h1:q8C3Kmk/vh2VhpCLaoR2MVWOGP8y7Jc8l82qCTd1DYI=
|
||||
github.com/go-openapi/swag/yamlutils v0.24.0 h1:bhw4894A7Iw6ne+639hsBNRHg9iZg/ISrOVr+sJGp4c=
|
||||
github.com/go-openapi/swag/yamlutils v0.24.0/go.mod h1:DpKv5aYuaGm/sULePoeiG8uwMpZSfReo1HR3Ik0yaG8=
|
||||
github.com/go-pkgz/routegroup v1.5.3 h1:IvH1KLcQkMap9jucQGBlef3IBloxSAe8USUFvxShFqs=
|
||||
github.com/go-pkgz/routegroup v1.5.3/go.mod h1:Pmu04fhgWhRtBMIJ8HXppnnzOPjnL/IEPBIdO2zmeqg=
|
||||
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
||||
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
|
||||
github.com/go-pkgz/routegroup v1.5.2 h1:/W/5GwsHaojeEBldiSB/fcqPLm0AE/eT36reCsMEbtY=
|
||||
github.com/go-pkgz/routegroup v1.5.2/go.mod h1:Pmu04fhgWhRtBMIJ8HXppnnzOPjnL/IEPBIdO2zmeqg=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
@@ -106,19 +84,20 @@ github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1
|
||||
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
||||
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/go-webauthn/webauthn v0.14.0 h1:ZLNPUgPcDlAeoxe+5umWG/tEeCoQIDr7gE2Zx2QnhL0=
|
||||
github.com/go-webauthn/webauthn v0.14.0/go.mod h1:QZzPFH3LJ48u5uEPAu+8/nWJImoLBWM7iAH/kSVSo6k=
|
||||
github.com/go-webauthn/x v0.1.25 h1:g/0noooIGcz/yCVqebcFgNnGIgBlJIccS+LYAa+0Z88=
|
||||
github.com/go-webauthn/x v0.1.25/go.mod h1:ieblaPY1/BVCV0oQTsA/VAo08/TWayQuJuo5Q+XxmTY=
|
||||
github.com/go-webauthn/webauthn v0.13.4 h1:q68qusWPcqHbg9STSxBLBHnsKaLxNO0RnVKaAqMuAuQ=
|
||||
github.com/go-webauthn/webauthn v0.13.4/go.mod h1:MglN6OH9ECxvhDqoq1wMoF6P6JRYDiQpC9nc5OomQmI=
|
||||
github.com/go-webauthn/x v0.1.23 h1:9lEO0s+g8iTyz5Vszlg/rXTGrx3CjcD0RZQ1GPZCaxI=
|
||||
github.com/go-webauthn/x v0.1.23/go.mod h1:AJd3hI7NfEp/4fI6T4CHD753u91l510lglU7/NMN6+E=
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
@@ -138,8 +117,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
||||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
|
||||
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||
@@ -160,6 +139,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
@@ -179,13 +160,13 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
||||
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
|
||||
github.com/mdlayher/netlink v1.8.0 h1:e7XNIYJKD7hUct3Px04RuIGJbBxy1/c4nX7D5YyvvlM=
|
||||
github.com/mdlayher/netlink v1.8.0/go.mod h1:UhgKXUlDQhzb09DrCl2GuRNEglHmhYoWAHid9HK3594=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/microsoft/go-mssqldb v1.8.2/go.mod h1:vp38dT33FGfVotRiTmDo3bFyaHq+p3LektQrjTULowo=
|
||||
github.com/microsoft/go-mssqldb v1.9.3 h1:hy4p+LDC8LIGvI3JATnLVmBOLMJbmn5X400mr5j0lPs=
|
||||
github.com/microsoft/go-mssqldb v1.9.3/go.mod h1:GBbW9ASTiDC+mpgWDGKdm3FnFLTUsLYN3iFL90lQ+PA=
|
||||
github.com/microsoft/go-mssqldb v1.9.2 h1:nY8TmFMQOHpm2qVWo6y4I2mAmVdZqlGiMGAYt64Ibbs=
|
||||
github.com/microsoft/go-mssqldb v1.9.2/go.mod h1:GBbW9ASTiDC+mpgWDGKdm3FnFLTUsLYN3iFL90lQ+PA=
|
||||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
|
||||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
@@ -204,14 +185,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus-community/pro-bing v0.7.0 h1:KFYFbxC2f2Fp6c+TyxbCOEarf7rbnzr9Gw8eIb0RfZA=
|
||||
github.com/prometheus-community/pro-bing v0.7.0/go.mod h1:Moob9dvlY50Bfq6i88xIwfyw7xLFHH69LUgx9n5zqCE=
|
||||
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
|
||||
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
|
||||
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
||||
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
|
||||
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
|
||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
@@ -229,8 +210,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
|
||||
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
|
||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
|
||||
@@ -255,12 +236,6 @@ github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
|
||||
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
@@ -273,18 +248,18 @@ golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOM
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/exp v0.0.0-20250808145144-a408d31f581a h1:Y+7uR/b1Mw2iSXZ3G//1haIiSElDQZ8KWh0h+sZPG90=
|
||||
golang.org/x/exp v0.0.0-20250808145144-a408d31f581a/go.mod h1:rT6SFzZ7oxADUDx58pcaKFTcZ+inxAa9fTrYx/uVYwg=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
@@ -304,8 +279,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
|
||||
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -313,8 +288,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -335,8 +310,8 @@ golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -365,8 +340,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
@@ -380,8 +355,8 @@ golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb h1:whnFRlWMcXI9d+Z
|
||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdIg1ozBNLgPy4SLT84nfcBjr6rhGtXYtrkWLU=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
@@ -399,20 +374,20 @@ gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXD
|
||||
gorm.io/driver/sqlserver v1.6.1 h1:XWISFsu2I2pqd1KJhhTZNJMx1jNQ+zVL/Q8ovDcUjtY=
|
||||
gorm.io/driver/sqlserver v1.6.1/go.mod h1:VZeNn7hqX1aXoN5TPAFGWvxWG90xtA8erGn2gQmpc6U=
|
||||
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
|
||||
gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY=
|
||||
gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||
modernc.org/cc/v4 v4.26.4 h1:jPhG8oNjtTYuP2FA4YefTJ/wioNUGALmGuEWt7SUR6s=
|
||||
modernc.org/cc/v4 v4.26.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A=
|
||||
modernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q=
|
||||
modernc.org/fileutil v1.3.28 h1:Vp156KUA2nPu9F1NEv036x9UGOjg2qsi5QlWTjZmtMk=
|
||||
modernc.org/fileutil v1.3.28/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
||||
gorm.io/gorm v1.30.1 h1:lSHg33jJTBxs2mgJRfRZeLDG+WZaHYCk3Wtfl6Ngzo4=
|
||||
gorm.io/gorm v1.30.1/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
|
||||
modernc.org/cc/v4 v4.26.3 h1:yEN8dzrkRFnn4PUUKXLYIqVf2PJYAEjMTFjO3BDGc3I=
|
||||
modernc.org/cc/v4 v4.26.3/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
|
||||
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
|
||||
modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM=
|
||||
modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.66.8 h1:/awsvTnyN/sNjvJm6S3lb7KZw5WV4ly/sBEG7ZUzmIE=
|
||||
modernc.org/libc v1.66.8/go.mod h1:aVdcY7udcawRqauu0HukYYxtBSizV+R80n/6aQe9D5k=
|
||||
modernc.org/libc v1.66.6 h1:RyQpwAhM/19nXD8y3iejM/AjmKwY2TjxZTlUWTsWw2U=
|
||||
modernc.org/libc v1.66.6/go.mod h1:j8z0EYAuumoMQ3+cWXtmw6m+LYn3qm8dcZDFtFTSq+M=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
@@ -427,5 +402,5 @@ modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|
@@ -3,13 +3,14 @@ package wgcontroller
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"log/slog"
|
||||
|
||||
"github.com/h44z/wg-portal/internal/config"
|
||||
"github.com/h44z/wg-portal/internal/domain"
|
||||
"github.com/h44z/wg-portal/internal/lowlevel"
|
||||
@@ -677,15 +678,11 @@ func (c *MikrotikController) updatePeer(
|
||||
extras := pp.GetExtras().(domain.MikrotikPeerExtras)
|
||||
peerId := extras.Id
|
||||
|
||||
endpoint := "" // by default, we have no endpoint (the peer does not initiate a connection)
|
||||
endpointPort := "0" // by default, we have no endpoint port (the peer does not initiate a connection)
|
||||
if !extras.IsResponder { // if the peer is not only a responder, it needs the endpoint to initiate a connection
|
||||
endpoint = pp.Endpoint
|
||||
endpointPort = "51820" // default port if not set
|
||||
if s := strings.Split(endpoint, ":"); len(s) == 2 {
|
||||
endpoint = s[0]
|
||||
endpointPort = s[1]
|
||||
}
|
||||
endpoint := pp.Endpoint
|
||||
endpointPort := "51820" // default port if not set
|
||||
if s := strings.Split(endpoint, ":"); len(s) == 2 {
|
||||
endpoint = s[0]
|
||||
endpointPort = s[1]
|
||||
}
|
||||
|
||||
allowedAddressStr := domain.CidrsToString(pp.AllowedIPs)
|
||||
|
@@ -43,7 +43,6 @@ type Peer struct {
|
||||
Identifier string `json:"Identifier" example:"super_nice_peer"` // peer unique identifier
|
||||
DisplayName string `json:"DisplayName"` // a nice display name/ description for the peer
|
||||
UserIdentifier string `json:"UserIdentifier"` // the owner
|
||||
UserDisplayName string `json:"UserDisplayName"` // the owner display name
|
||||
InterfaceIdentifier string `json:"InterfaceIdentifier"` // the interface id
|
||||
Disabled bool `json:"Disabled"` // flag that specifies if the peer is enabled (up) or not (down)
|
||||
DisabledReason string `json:"DisabledReason"` // the reason why the peer has been disabled
|
||||
@@ -81,7 +80,7 @@ type Peer struct {
|
||||
}
|
||||
|
||||
func NewPeer(src *domain.Peer) *Peer {
|
||||
p := &Peer{
|
||||
return &Peer{
|
||||
Identifier: string(src.Identifier),
|
||||
DisplayName: src.DisplayName,
|
||||
UserIdentifier: string(src.UserIdentifier),
|
||||
@@ -112,12 +111,6 @@ func NewPeer(src *domain.Peer) *Peer {
|
||||
PostDown: ConfigOptionFromDomain(src.Interface.PostDown),
|
||||
Filename: src.GetConfigFileName(),
|
||||
}
|
||||
|
||||
if src.User != nil {
|
||||
p.UserDisplayName = src.User.DisplayName()
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func NewPeers(src []domain.Peer) []Peer {
|
||||
|
@@ -52,12 +52,8 @@ func Initialize(
|
||||
// Switch to admin user context
|
||||
startupContext = domain.SetUserInfo(startupContext, domain.SystemAdminContextUserInfo())
|
||||
|
||||
if !cfg.Core.AdminUserDisabled {
|
||||
if err := a.createDefaultUser(startupContext); err != nil {
|
||||
return fmt.Errorf("failed to create default user: %w", err)
|
||||
}
|
||||
} else {
|
||||
slog.Info("Local Admin user disabled!")
|
||||
if err := a.createDefaultUser(startupContext); err != nil {
|
||||
return fmt.Errorf("failed to create default user: %w", err)
|
||||
}
|
||||
|
||||
if err := a.importNewInterfaces(startupContext); err != nil {
|
||||
|
@@ -125,27 +125,11 @@ func NewAuthenticator(cfg *config.Auth, extUrl string, bus EventBus, users UserM
|
||||
// It sets up the external authentication providers (OIDC, OAuth, LDAP) and retries in case of errors.
|
||||
func (a *Authenticator) StartBackgroundJobs(ctx context.Context) {
|
||||
go func() {
|
||||
slog.Debug("setting up external auth providers...")
|
||||
|
||||
// Initialize local copies of authentication providers to allow retry in case of errors
|
||||
oidcQueue := a.cfg.OpenIDConnect
|
||||
oauthQueue := a.cfg.OAuth
|
||||
ldapQueue := a.cfg.Ldap
|
||||
|
||||
// Immediate attempt
|
||||
failedOidc, failedOauth, failedLdap := a.setupExternalAuthProviders(oidcQueue, oauthQueue, ldapQueue)
|
||||
if len(failedOidc) == 0 && len(failedOauth) == 0 && len(failedLdap) == 0 {
|
||||
slog.Info("successfully setup all external auth providers")
|
||||
return
|
||||
}
|
||||
|
||||
// Prepare for retries with only the failed ones
|
||||
oidcQueue = failedOidc
|
||||
oauthQueue = failedOauth
|
||||
ldapQueue = failedLdap
|
||||
slog.Warn("failed to setup some external auth providers, retrying in 30 seconds",
|
||||
"failedOidc", len(failedOidc), "failedOauth", len(failedOauth), "failedLdap", len(failedLdap))
|
||||
|
||||
ticker := time.NewTicker(30 * time.Second) // Ticker for delay between retries
|
||||
defer ticker.Stop()
|
||||
|
||||
@@ -380,7 +364,6 @@ func (a *Authenticator) passwordAuthentication(
|
||||
}
|
||||
ldapUserInfo, err = ldapAuth.ParseUserInfo(rawUserInfo)
|
||||
if err != nil {
|
||||
slog.Error("failed to parse ldap user info", "identifier", identifier, "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -393,13 +376,10 @@ func (a *Authenticator) passwordAuthentication(
|
||||
}
|
||||
|
||||
if userSource == "" {
|
||||
slog.Warn("no user source found for user", "identifier", identifier, "ldapProviderCount", a.ldapAuthenticators)
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
|
||||
if userSource == domain.UserSourceLdap && ldapProvider == nil {
|
||||
slog.Warn("no ldap provider found for user",
|
||||
"identifier", identifier, "ldapProviderCount", a.ldapAuthenticators)
|
||||
return nil, errors.New("ldap provider not found")
|
||||
}
|
||||
|
||||
|
@@ -54,7 +54,7 @@ func (l LdapAuthenticator) PlaintextAuthentication(userId domain.UserIdentifier,
|
||||
|
||||
attrs := []string{"dn"}
|
||||
|
||||
loginFilter := strings.Replace(l.cfg.LoginFilter, "{{login_identifier}}", ldap.EscapeFilter(string(userId)), -1)
|
||||
loginFilter := strings.Replace(l.cfg.LoginFilter, "{{login_identifier}}", string(userId), -1)
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
l.cfg.BaseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 20, false, // 20 second time limit
|
||||
@@ -100,7 +100,7 @@ func (l LdapAuthenticator) GetUserInfo(_ context.Context, userId domain.UserIden
|
||||
|
||||
attrs := internal.LdapSearchAttributes(&l.cfg.FieldMap)
|
||||
|
||||
loginFilter := strings.Replace(l.cfg.LoginFilter, "{{login_identifier}}", ldap.EscapeFilter(string(userId)), -1)
|
||||
loginFilter := strings.Replace(l.cfg.LoginFilter, "{{login_identifier}}", string(userId), -1)
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
l.cfg.BaseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 20, false, // 20 second time limit
|
||||
|
@@ -82,9 +82,8 @@ func (c *ControllerManager) registerLocalController() error {
|
||||
|
||||
c.controllers[config.LocalBackendName] = backendInstance{
|
||||
Config: config.BackendBase{
|
||||
Id: config.LocalBackendName,
|
||||
DisplayName: "Local WireGuard Controller",
|
||||
IgnoredInterfaces: c.cfg.Backend.IgnoredLocalInterfaces,
|
||||
Id: config.LocalBackendName,
|
||||
DisplayName: "Local WireGuard Controller",
|
||||
},
|
||||
Implementation: localController,
|
||||
}
|
||||
@@ -119,17 +118,17 @@ func (c *ControllerManager) logRegisteredControllers() {
|
||||
}
|
||||
|
||||
func (c *ControllerManager) GetControllerByName(backend domain.InterfaceBackend) InterfaceController {
|
||||
return c.getController(backend, "").Implementation
|
||||
return c.getController(backend, "")
|
||||
}
|
||||
|
||||
func (c *ControllerManager) GetController(iface domain.Interface) InterfaceController {
|
||||
return c.getController(iface.Backend, iface.Identifier).Implementation
|
||||
return c.getController(iface.Backend, iface.Identifier)
|
||||
}
|
||||
|
||||
func (c *ControllerManager) getController(
|
||||
backend domain.InterfaceBackend,
|
||||
ifaceId domain.InterfaceIdentifier,
|
||||
) backendInstance {
|
||||
) InterfaceController {
|
||||
if backend == "" {
|
||||
// If no backend is specified, use the local controller.
|
||||
// This might be the case for interfaces created in previous WireGuard Portal versions.
|
||||
@@ -146,13 +145,13 @@ func (c *ControllerManager) getController(
|
||||
slog.Warn("controller for backend not found, using local controller",
|
||||
"backend", backend, "interface", ifaceId)
|
||||
}
|
||||
return controller
|
||||
return controller.Implementation
|
||||
}
|
||||
|
||||
func (c *ControllerManager) GetAllControllers() []backendInstance {
|
||||
var backendInstances = make([]backendInstance, 0, len(c.controllers))
|
||||
func (c *ControllerManager) GetAllControllers() []InterfaceController {
|
||||
var backendInstances = make([]InterfaceController, 0, len(c.controllers))
|
||||
for instance := range maps.Values(c.controllers) {
|
||||
backendInstances = append(backendInstances, instance)
|
||||
backendInstances = append(backendInstances, instance.Implementation)
|
||||
}
|
||||
return backendInstances
|
||||
}
|
||||
|
@@ -15,6 +15,26 @@ import (
|
||||
"github.com/h44z/wg-portal/internal/domain"
|
||||
)
|
||||
|
||||
// GetImportableInterfaces returns all physical interfaces that are available on the system.
|
||||
// This function also returns interfaces that are already available in the database.
|
||||
func (m Manager) GetImportableInterfaces(ctx context.Context) ([]domain.PhysicalInterface, error) {
|
||||
if err := domain.ValidateAdminAccessRights(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var allPhysicalInterfaces []domain.PhysicalInterface
|
||||
for _, wgBackend := range m.wg.GetAllControllers() {
|
||||
physicalInterfaces, err := wgBackend.GetInterfaces(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allPhysicalInterfaces = append(allPhysicalInterfaces, physicalInterfaces...)
|
||||
}
|
||||
|
||||
return allPhysicalInterfaces, nil
|
||||
}
|
||||
|
||||
// GetInterfaceAndPeers returns the interface and all peers for the given interface identifier.
|
||||
func (m Manager) GetInterfaceAndPeers(ctx context.Context, id domain.InterfaceIdentifier) (
|
||||
*domain.Interface,
|
||||
@@ -90,62 +110,52 @@ func (m Manager) GetUserInterfaces(ctx context.Context, _ domain.UserIdentifier)
|
||||
}
|
||||
|
||||
// ImportNewInterfaces imports all new physical interfaces that are available on the system.
|
||||
// If a filter is set, only interfaces that match the filter will be imported.
|
||||
func (m Manager) ImportNewInterfaces(ctx context.Context, filter ...domain.InterfaceIdentifier) (int, error) {
|
||||
if err := domain.ValidateAdminAccessRights(ctx); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var existingInterfaceIds []domain.InterfaceIdentifier
|
||||
existingInterfaces, err := m.db.GetAllInterfaces(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for _, existingInterface := range existingInterfaces {
|
||||
existingInterfaceIds = append(existingInterfaceIds, existingInterface.Identifier)
|
||||
}
|
||||
|
||||
imported := 0
|
||||
for _, wgBackend := range m.wg.GetAllControllers() {
|
||||
physicalInterfaces, err := wgBackend.Implementation.GetInterfaces(ctx)
|
||||
physicalInterfaces, err := wgBackend.GetInterfaces(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// if no filter is given, exclude already existing interfaces
|
||||
var excludedInterfaces []domain.InterfaceIdentifier
|
||||
if len(filter) == 0 {
|
||||
existingInterfaces, err := m.db.GetAllInterfaces(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for _, existingInterface := range existingInterfaces {
|
||||
excludedInterfaces = append(excludedInterfaces, existingInterface.Identifier)
|
||||
}
|
||||
}
|
||||
|
||||
for _, physicalInterface := range physicalInterfaces {
|
||||
if slices.Contains(wgBackend.Config.IgnoredInterfaces, string(physicalInterface.Identifier)) {
|
||||
slog.Info("ignoring interface due to backend filter restrictions",
|
||||
"interface", physicalInterface.Identifier, "filter", wgBackend.Config.IgnoredInterfaces,
|
||||
"backend", wgBackend.Config.Id)
|
||||
continue // skip ignored interfaces
|
||||
}
|
||||
|
||||
if slices.Contains(existingInterfaceIds, physicalInterface.Identifier) {
|
||||
continue // skip interfaces that already exist
|
||||
}
|
||||
|
||||
if len(filter) > 0 && !slices.Contains(filter, physicalInterface.Identifier) {
|
||||
slog.Info("ignoring interface due to filter restrictions",
|
||||
"interface", physicalInterface.Identifier, "filter", wgBackend.Config.IgnoredInterfaces,
|
||||
"backend", wgBackend.Config.Id)
|
||||
if slices.Contains(excludedInterfaces, physicalInterface.Identifier) {
|
||||
continue
|
||||
}
|
||||
|
||||
slog.Info("importing new interface",
|
||||
"interface", physicalInterface.Identifier, "backend", wgBackend.Config.Id)
|
||||
if len(filter) != 0 && !slices.Contains(filter, physicalInterface.Identifier) {
|
||||
continue
|
||||
}
|
||||
|
||||
physicalPeers, err := wgBackend.Implementation.GetPeers(ctx, physicalInterface.Identifier)
|
||||
slog.Info("importing new interface", "interface", physicalInterface.Identifier)
|
||||
|
||||
physicalPeers, err := wgBackend.GetPeers(ctx, physicalInterface.Identifier)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
err = m.importInterface(ctx, wgBackend.Implementation, &physicalInterface, physicalPeers)
|
||||
err = m.importInterface(ctx, wgBackend, &physicalInterface, physicalPeers)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("import of %s failed: %w", physicalInterface.Identifier, err)
|
||||
}
|
||||
|
||||
slog.Info("imported new interface",
|
||||
"interface", physicalInterface.Identifier, "peers", len(physicalPeers), "backend", wgBackend.Config.Id)
|
||||
slog.Info("imported new interface", "interface", physicalInterface.Identifier, "peers", len(physicalPeers))
|
||||
imported++
|
||||
}
|
||||
}
|
||||
@@ -211,11 +221,9 @@ func (m Manager) RestoreInterfaceState(
|
||||
return fmt.Errorf("failed to load peers for %s: %w", iface.Identifier, err)
|
||||
}
|
||||
|
||||
controller := m.wg.GetController(iface)
|
||||
|
||||
_, err = controller.GetInterface(ctx, iface.Identifier)
|
||||
_, err = m.wg.GetController(iface).GetInterface(ctx, iface.Identifier)
|
||||
if err != nil && !iface.IsDisabled() {
|
||||
slog.Debug("creating missing interface", "interface", iface.Identifier, "backend", controller.GetId())
|
||||
slog.Debug("creating missing interface", "interface", iface.Identifier)
|
||||
|
||||
// temporarily disable interface in database so that the current state is reflected correctly
|
||||
_ = m.db.SaveInterface(ctx, iface.Identifier,
|
||||
@@ -242,8 +250,7 @@ func (m Manager) RestoreInterfaceState(
|
||||
return fmt.Errorf("failed to create physical interface %s: %w", iface.Identifier, err)
|
||||
}
|
||||
} else {
|
||||
slog.Debug("restoring interface state",
|
||||
"interface", iface.Identifier, "disabled", iface.IsDisabled(), "backend", controller.GetId())
|
||||
slog.Debug("restoring interface state", "interface", iface.Identifier, "disabled", iface.IsDisabled())
|
||||
|
||||
// try to move interface to stored state
|
||||
_, err = m.saveInterface(ctx, &iface)
|
||||
@@ -271,13 +278,13 @@ func (m Manager) RestoreInterfaceState(
|
||||
for _, peer := range peers {
|
||||
switch {
|
||||
case iface.IsDisabled() && iface.Backend == config.LocalBackendName: // if interface is disabled, delete all peers
|
||||
if err := controller.DeletePeer(ctx, iface.Identifier,
|
||||
if err := m.wg.GetController(iface).DeletePeer(ctx, iface.Identifier,
|
||||
peer.Identifier); err != nil {
|
||||
return fmt.Errorf("failed to remove peer %s for disabled interface %s: %w",
|
||||
peer.Identifier, iface.Identifier, err)
|
||||
}
|
||||
default: // update peer
|
||||
err := controller.SavePeer(ctx, iface.Identifier, peer.Identifier,
|
||||
err := m.wg.GetController(iface).SavePeer(ctx, iface.Identifier, peer.Identifier,
|
||||
func(pp *domain.PhysicalPeer) (*domain.PhysicalPeer, error) {
|
||||
domain.MergeToPhysicalPeer(pp, &peer)
|
||||
return pp, nil
|
||||
@@ -290,7 +297,7 @@ func (m Manager) RestoreInterfaceState(
|
||||
}
|
||||
|
||||
// remove non-wgportal peers
|
||||
physicalPeers, _ := controller.GetPeers(ctx, iface.Identifier)
|
||||
physicalPeers, _ := m.wg.GetController(iface).GetPeers(ctx, iface.Identifier)
|
||||
for _, physicalPeer := range physicalPeers {
|
||||
isWgPortalPeer := false
|
||||
for _, peer := range peers {
|
||||
@@ -300,7 +307,7 @@ func (m Manager) RestoreInterfaceState(
|
||||
}
|
||||
}
|
||||
if !isWgPortalPeer {
|
||||
err := controller.DeletePeer(ctx, iface.Identifier,
|
||||
err := m.wg.GetController(iface).DeletePeer(ctx, iface.Identifier,
|
||||
domain.PeerIdentifier(physicalPeer.PublicKey))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to remove non-wgportal peer %s from interface %s: %w",
|
||||
@@ -544,30 +551,6 @@ func (m Manager) saveInterface(ctx context.Context, iface *domain.Interface) (
|
||||
return nil, fmt.Errorf("failed to save interface: %w", err)
|
||||
}
|
||||
|
||||
// update the interface type of peers in db
|
||||
peers, err := m.db.GetInterfacePeers(ctx, iface.Identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load peers for interface %s: %w", iface.Identifier, err)
|
||||
}
|
||||
for _, peer := range peers {
|
||||
err := m.db.SavePeer(ctx, peer.Identifier, func(_ *domain.Peer) (*domain.Peer, error) {
|
||||
switch iface.Type {
|
||||
case domain.InterfaceTypeAny:
|
||||
peer.Interface.Type = domain.InterfaceTypeAny
|
||||
case domain.InterfaceTypeClient:
|
||||
peer.Interface.Type = domain.InterfaceTypeServer
|
||||
case domain.InterfaceTypeServer:
|
||||
peer.Interface.Type = domain.InterfaceTypeClient
|
||||
}
|
||||
|
||||
return &peer, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update peer %s for interface %s: %w", peer.Identifier,
|
||||
iface.Identifier, err)
|
||||
}
|
||||
}
|
||||
|
||||
if iface.IsDisabled() {
|
||||
physicalInterface, _ := m.wg.GetController(*iface).GetInterface(ctx, iface.Identifier)
|
||||
fwMark := iface.FirewallMark
|
||||
|
@@ -188,8 +188,6 @@ func (m Manager) CreatePeer(ctx context.Context, peer *domain.Peer) (*domain.Pee
|
||||
|
||||
sessionUser := domain.GetUserInfo(ctx)
|
||||
|
||||
peer.Identifier = domain.PeerIdentifier(peer.Interface.PublicKey) // ensure that identifier corresponds to the public key
|
||||
|
||||
// Enforce peer limit for non-admin users if LimitAdditionalUserPeers is set
|
||||
if m.cfg.Core.SelfProvisioningAllowed && !sessionUser.IsAdmin && m.cfg.Advanced.LimitAdditionalUserPeers > 0 {
|
||||
peers, err := m.db.GetUserPeers(ctx, peer.UserIdentifier)
|
||||
|
@@ -1,194 +0,0 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/h44z/wg-portal/internal/config"
|
||||
"github.com/h44z/wg-portal/internal/domain"
|
||||
)
|
||||
|
||||
// --- Test mocks ---
|
||||
|
||||
type mockBus struct{}
|
||||
|
||||
func (f *mockBus) Publish(topic string, args ...any) {}
|
||||
func (f *mockBus) Subscribe(topic string, fn interface{}) error { return nil }
|
||||
|
||||
type mockController struct{}
|
||||
|
||||
func (f *mockController) GetId() domain.InterfaceBackend { return "local" }
|
||||
func (f *mockController) GetInterfaces(_ context.Context) ([]domain.PhysicalInterface, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *mockController) GetInterface(_ context.Context, id domain.InterfaceIdentifier) (
|
||||
*domain.PhysicalInterface,
|
||||
error,
|
||||
) {
|
||||
return &domain.PhysicalInterface{Identifier: id}, nil
|
||||
}
|
||||
func (f *mockController) GetPeers(_ context.Context, _ domain.InterfaceIdentifier) ([]domain.PhysicalPeer, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *mockController) SaveInterface(
|
||||
_ context.Context,
|
||||
_ domain.InterfaceIdentifier,
|
||||
updateFunc func(pi *domain.PhysicalInterface) (*domain.PhysicalInterface, error),
|
||||
) error {
|
||||
_, _ = updateFunc(&domain.PhysicalInterface{})
|
||||
return nil
|
||||
}
|
||||
func (f *mockController) DeleteInterface(_ context.Context, _ domain.InterfaceIdentifier) error {
|
||||
return nil
|
||||
}
|
||||
func (f *mockController) SavePeer(
|
||||
_ context.Context,
|
||||
_ domain.InterfaceIdentifier,
|
||||
_ domain.PeerIdentifier,
|
||||
updateFunc func(pp *domain.PhysicalPeer) (*domain.PhysicalPeer, error),
|
||||
) error {
|
||||
_, _ = updateFunc(&domain.PhysicalPeer{})
|
||||
return nil
|
||||
}
|
||||
func (f *mockController) DeletePeer(_ context.Context, _ domain.InterfaceIdentifier, _ domain.PeerIdentifier) error {
|
||||
return nil
|
||||
}
|
||||
func (f *mockController) PingAddresses(_ context.Context, _ string) (*domain.PingerResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type mockDB struct {
|
||||
savedPeers map[domain.PeerIdentifier]*domain.Peer
|
||||
iface *domain.Interface
|
||||
}
|
||||
|
||||
func (f *mockDB) GetInterface(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, error) {
|
||||
if f.iface != nil && f.iface.Identifier == id {
|
||||
return f.iface, nil
|
||||
}
|
||||
return &domain.Interface{Identifier: id}, nil
|
||||
}
|
||||
func (f *mockDB) GetInterfaceAndPeers(ctx context.Context, id domain.InterfaceIdentifier) (
|
||||
*domain.Interface,
|
||||
[]domain.Peer,
|
||||
error,
|
||||
) {
|
||||
return f.iface, nil, nil
|
||||
}
|
||||
func (f *mockDB) GetPeersStats(ctx context.Context, ids ...domain.PeerIdentifier) ([]domain.PeerStatus, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *mockDB) GetAllInterfaces(ctx context.Context) ([]domain.Interface, error) { return nil, nil }
|
||||
func (f *mockDB) GetInterfaceIps(ctx context.Context) (map[domain.InterfaceIdentifier][]domain.Cidr, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *mockDB) SaveInterface(
|
||||
ctx context.Context,
|
||||
id domain.InterfaceIdentifier,
|
||||
updateFunc func(in *domain.Interface) (*domain.Interface, error),
|
||||
) error {
|
||||
if f.iface == nil {
|
||||
f.iface = &domain.Interface{Identifier: id}
|
||||
}
|
||||
var err error
|
||||
f.iface, err = updateFunc(f.iface)
|
||||
return err
|
||||
}
|
||||
func (f *mockDB) DeleteInterface(ctx context.Context, id domain.InterfaceIdentifier) error {
|
||||
return nil
|
||||
}
|
||||
func (f *mockDB) GetInterfacePeers(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.Peer, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *mockDB) GetUserPeers(ctx context.Context, id domain.UserIdentifier) ([]domain.Peer, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *mockDB) SavePeer(
|
||||
ctx context.Context,
|
||||
id domain.PeerIdentifier,
|
||||
updateFunc func(in *domain.Peer) (*domain.Peer, error),
|
||||
) error {
|
||||
if f.savedPeers == nil {
|
||||
f.savedPeers = make(map[domain.PeerIdentifier]*domain.Peer)
|
||||
}
|
||||
existing := f.savedPeers[id]
|
||||
if existing == nil {
|
||||
existing = &domain.Peer{Identifier: id}
|
||||
}
|
||||
updated, err := updateFunc(existing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.savedPeers[updated.Identifier] = updated
|
||||
return nil
|
||||
}
|
||||
func (f *mockDB) DeletePeer(ctx context.Context, id domain.PeerIdentifier) error { return nil }
|
||||
func (f *mockDB) GetPeer(ctx context.Context, id domain.PeerIdentifier) (*domain.Peer, error) {
|
||||
return nil, domain.ErrNotFound
|
||||
}
|
||||
func (f *mockDB) GetUsedIpsPerSubnet(ctx context.Context, subnets []domain.Cidr) (
|
||||
map[domain.Cidr][]domain.Cidr,
|
||||
error,
|
||||
) {
|
||||
return map[domain.Cidr][]domain.Cidr{}, nil
|
||||
}
|
||||
|
||||
// --- Test ---
|
||||
|
||||
func TestCreatePeer_SetsIdentifier_FromPublicKey(t *testing.T) {
|
||||
// Arrange
|
||||
cfg := &config.Config{}
|
||||
cfg.Core.SelfProvisioningAllowed = true
|
||||
cfg.Core.EditableKeys = true
|
||||
cfg.Advanced.LimitAdditionalUserPeers = 0
|
||||
|
||||
bus := &mockBus{}
|
||||
|
||||
// Prepare a controller manager with our mock controller
|
||||
ctrlMgr := &ControllerManager{
|
||||
controllers: map[domain.InterfaceBackend]backendInstance{
|
||||
config.LocalBackendName: {Implementation: &mockController{}},
|
||||
},
|
||||
}
|
||||
|
||||
db := &mockDB{iface: &domain.Interface{Identifier: "wg0", Type: domain.InterfaceTypeServer}}
|
||||
|
||||
m := Manager{
|
||||
cfg: cfg,
|
||||
bus: bus,
|
||||
db: db,
|
||||
wg: ctrlMgr,
|
||||
}
|
||||
|
||||
userId := domain.UserIdentifier("user@example.com")
|
||||
ctx := domain.SetUserInfo(context.Background(), &domain.ContextUserInfo{Id: userId, IsAdmin: false})
|
||||
|
||||
pubKey := "TEST_PUBLIC_KEY_ABC123"
|
||||
|
||||
input := &domain.Peer{
|
||||
Identifier: "should_be_overwritten",
|
||||
UserIdentifier: userId,
|
||||
InterfaceIdentifier: domain.InterfaceIdentifier("wg0"),
|
||||
Interface: domain.PeerInterfaceConfig{
|
||||
KeyPair: domain.KeyPair{PublicKey: pubKey},
|
||||
},
|
||||
}
|
||||
|
||||
// Act
|
||||
out, err := m.CreatePeer(ctx, input)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
t.Fatalf("CreatePeer returned error: %v", err)
|
||||
}
|
||||
|
||||
expectedId := domain.PeerIdentifier(pubKey)
|
||||
if out.Identifier != expectedId {
|
||||
t.Fatalf("expected Identifier to be set from public key %q, got %q", expectedId, out.Identifier)
|
||||
}
|
||||
|
||||
// Ensure the saved peer in DB also has the expected identifier
|
||||
if db.savedPeers[expectedId] == nil {
|
||||
t.Fatalf("expected peer with identifier %q to be saved in DB", expectedId)
|
||||
}
|
||||
}
|
@@ -10,12 +10,6 @@ const LocalBackendName = "local"
|
||||
type Backend struct {
|
||||
Default string `yaml:"default"` // The default backend to use (defaults to the internal backend)
|
||||
|
||||
// Local Backend-specific configuration
|
||||
|
||||
IgnoredLocalInterfaces []string `yaml:"ignored_local_interfaces"` // A list of interface names that should be ignored by this backend (e.g., "wg0")
|
||||
|
||||
// External Backend-specific configuration
|
||||
|
||||
Mikrotik []BackendMikrotik `yaml:"mikrotik"`
|
||||
}
|
||||
|
||||
@@ -48,8 +42,6 @@ func (b *Backend) Validate() error {
|
||||
type BackendBase struct {
|
||||
Id string `yaml:"id"` // A unique id for the backend
|
||||
DisplayName string `yaml:"display_name"` // A display name for the backend
|
||||
|
||||
IgnoredInterfaces []string `yaml:"ignored_interfaces"` // A list of interface names that should be ignored by this backend (e.g., "wg0")
|
||||
}
|
||||
|
||||
// GetDisplayName returns the display name of the backend.
|
||||
|
@@ -14,10 +14,9 @@ import (
|
||||
type Config struct {
|
||||
Core struct {
|
||||
// AdminUser defines the default administrator account that will be created
|
||||
AdminUserDisabled bool `yaml:"disable_admin_user"`
|
||||
AdminUser string `yaml:"admin_user"`
|
||||
AdminPassword string `yaml:"admin_password"`
|
||||
AdminApiToken string `yaml:"admin_api_token"` // if set, the API access is enabled automatically
|
||||
AdminUser string `yaml:"admin_user"`
|
||||
AdminPassword string `yaml:"admin_password"`
|
||||
AdminApiToken string `yaml:"admin_api_token"` // if set, the API access is enabled automatically
|
||||
|
||||
EditableKeys bool `yaml:"editable_keys"`
|
||||
CreateDefaultPeer bool `yaml:"create_default_peer"`
|
||||
@@ -114,7 +113,6 @@ func (c *Config) LogStartupValues() {
|
||||
func defaultConfig() *Config {
|
||||
cfg := &Config{}
|
||||
|
||||
cfg.Core.AdminUserDisabled = false
|
||||
cfg.Core.AdminUser = "admin@wgportal.local"
|
||||
cfg.Core.AdminPassword = "wgportal-default"
|
||||
cfg.Core.AdminApiToken = "" // by default, the API access is disabled
|
||||
|
@@ -1,14 +1,12 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/h44z/wg-portal/internal"
|
||||
"github.com/h44z/wg-portal/internal/config"
|
||||
@@ -46,7 +44,6 @@ type Peer struct {
|
||||
DisplayName string // a nice display name/ description for the peer
|
||||
Identifier PeerIdentifier `gorm:"primaryKey;column:identifier"` // peer unique identifier
|
||||
UserIdentifier UserIdentifier `gorm:"index;column:user_identifier"` // the owner
|
||||
User *User `gorm:"-"` // the owner user object; loaded automatically after fetch
|
||||
InterfaceIdentifier InterfaceIdentifier `gorm:"index;column:interface_identifier"` // the interface id
|
||||
Disabled *time.Time `gorm:"column:disabled"` // if this field is set, the peer is disabled
|
||||
DisabledReason string // the reason why the peer has been disabled
|
||||
@@ -331,7 +328,7 @@ func MergeToPhysicalPeer(pp *PhysicalPeer, p *Peer) {
|
||||
Id: "",
|
||||
Name: p.DisplayName,
|
||||
Comment: p.Notes,
|
||||
IsResponder: p.Interface.Type == InterfaceTypeClient,
|
||||
IsResponder: false,
|
||||
Disabled: p.IsDisabled(),
|
||||
ClientEndpoint: p.Endpoint.GetValue(),
|
||||
ClientAddress: CidrsToString(p.Interface.Addresses),
|
||||
@@ -351,26 +348,3 @@ type PeerCreationRequest struct {
|
||||
UserIdentifiers []string
|
||||
Prefix string
|
||||
}
|
||||
|
||||
// AfterFind is a GORM hook that automatically loads the associated User object
|
||||
// based on the UserIdentifier field. If the identifier is empty or no user is
|
||||
// found, the User field is set to nil.
|
||||
func (p *Peer) AfterFind(tx *gorm.DB) error {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
if p.UserIdentifier == "" {
|
||||
p.User = nil
|
||||
return nil
|
||||
}
|
||||
var u User
|
||||
if err := tx.Where("identifier = ?", p.UserIdentifier).First(&u).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
p.User = nil
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
p.User = &u
|
||||
return nil
|
||||
}
|
||||
|
@@ -185,27 +185,6 @@ func (u *User) CopyCalculatedAttributes(src *User) {
|
||||
u.LinkedPeerCount = src.LinkedPeerCount
|
||||
}
|
||||
|
||||
// DisplayName returns the display name of the user.
|
||||
// The display name is the first and last name, or the email address of the user.
|
||||
// If none of these fields are set, the user identifier is returned.
|
||||
func (u *User) DisplayName() string {
|
||||
var displayName string
|
||||
switch {
|
||||
case u.Firstname != "" && u.Lastname != "":
|
||||
displayName = fmt.Sprintf("%s %s", u.Firstname, u.Lastname)
|
||||
case u.Firstname != "":
|
||||
displayName = u.Firstname
|
||||
case u.Lastname != "":
|
||||
displayName = u.Lastname
|
||||
case u.Email != "":
|
||||
displayName = u.Email
|
||||
default:
|
||||
displayName = string(u.Identifier)
|
||||
}
|
||||
|
||||
return displayName
|
||||
}
|
||||
|
||||
// region webauthn
|
||||
|
||||
func (u *User) WebAuthnID() []byte {
|
||||
@@ -230,7 +209,19 @@ func (u *User) WebAuthnName() string {
|
||||
}
|
||||
|
||||
func (u *User) WebAuthnDisplayName() string {
|
||||
return u.DisplayName()
|
||||
var userName string
|
||||
switch {
|
||||
case u.Firstname != "" && u.Lastname != "":
|
||||
userName = fmt.Sprintf("%s %s", u.Firstname, u.Lastname)
|
||||
case u.Firstname != "":
|
||||
userName = u.Firstname
|
||||
case u.Lastname != "":
|
||||
userName = u.Lastname
|
||||
default:
|
||||
userName = string(u.Identifier)
|
||||
}
|
||||
|
||||
return userName
|
||||
}
|
||||
|
||||
func (u *User) WebAuthnCredentials() []webauthn.Credential {
|
||||
|
Reference in New Issue
Block a user