mirror of
https://github.com/h44z/wg-portal.git
synced 2025-08-10 07:22:24 +00:00
more cleanup
This commit is contained in:
parent
4b3225e293
commit
93f8633b2b
@ -42,12 +42,9 @@ COPY --from=builder /etc/group /etc/group
|
|||||||
|
|
||||||
# Copy binaries
|
# Copy binaries
|
||||||
COPY --from=builder /build/dist/wg-portal /app/wg-portal
|
COPY --from=builder /build/dist/wg-portal /app/wg-portal
|
||||||
COPY --from=builder /build/dist/hc /app/hc
|
|
||||||
|
|
||||||
# Set the Current Working Directory inside the container
|
# Set the Current Working Directory inside the container
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Command to run the executable
|
# Command to run the executable
|
||||||
CMD [ "/app/wg-portal" ]
|
CMD [ "/app/wg-portal" ]
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 CMD [ "/app/hc", "http://localhost:11223/health" ]
|
|
222
README.md
222
README.md
@ -1,4 +1,4 @@
|
|||||||
# WireGuard Portal
|
# WireGuard Portal (V2 - alpha testing)
|
||||||
|
|
||||||
[](https://travis-ci.com/h44z/wg-portal)
|
[](https://travis-ci.com/h44z/wg-portal)
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||
@ -8,6 +8,9 @@
|
|||||||

|

|
||||||
[](https://hub.docker.com/r/h44z/wg-portal/)
|
[](https://hub.docker.com/r/h44z/wg-portal/)
|
||||||
|
|
||||||
|
> :warning: **IMPORTANT** Version 2 is currently under development and may contain bugs. It is currently not advised to use this version
|
||||||
|
in production. Use version [1.0.17](https://github.com/h44z/wg-portal/releases) instead.
|
||||||
|
|
||||||
A simple, web based configuration portal for [WireGuard](https://wireguard.com).
|
A simple, web based configuration portal for [WireGuard](https://wireguard.com).
|
||||||
The portal uses the WireGuard [wgctrl](https://github.com/WireGuard/wgctrl-go) library to manage existing VPN
|
The portal uses the WireGuard [wgctrl](https://github.com/WireGuard/wgctrl-go) library to manage existing VPN
|
||||||
interfaces. This allows for seamless activation or deactivation of new users, without disturbing existing VPN
|
interfaces. This allows for seamless activation or deactivation of new users, without disturbing existing VPN
|
||||||
@ -15,25 +18,27 @@ connections.
|
|||||||
|
|
||||||
The configuration portal supports using a database (SQLite, MySQL, MsSQL or Postgres), OAuth or LDAP (Active Directory or OpenLDAP) as a user source for authentication and profile data.
|
The configuration portal supports using a database (SQLite, MySQL, MsSQL or Postgres), OAuth or LDAP (Active Directory or OpenLDAP) as a user source for authentication and profile data.
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Self-hosted and web based
|
* Self-hosted - the whole application is a single binary
|
||||||
|
* Responsive web UI written in Vue.JS
|
||||||
* Automatically select IP from the network pool assigned to client
|
* Automatically select IP from the network pool assigned to client
|
||||||
* QR-Code for convenient mobile client configuration
|
* QR-Code for convenient mobile client configuration
|
||||||
* Sent email to client with QR-code and client config
|
* Sent email to client with QR-code and client config
|
||||||
* Enable / Disable clients seamlessly
|
* Enable / Disable clients seamlessly
|
||||||
* Generation of `wgX.conf` if required
|
* Generation of wg-quick configuration file (`wgX.conf`) if required
|
||||||
|
* User authentication (database, OAuth or LDAP)
|
||||||
* IPv6 ready
|
* IPv6 ready
|
||||||
* User authentication (database, OAuth or LDAP)
|
* Docker ready
|
||||||
* Dockerized
|
|
||||||
* Responsive web UI written in Vue.JS
|
|
||||||
* One single binary
|
|
||||||
* Can be used with existing WireGuard setups
|
* Can be used with existing WireGuard setups
|
||||||
* Support for multiple WireGuard interfaces
|
* Support for multiple WireGuard interfaces
|
||||||
* Peer Expiry Feature
|
* Peer Expiry Feature
|
||||||
* REST API for management and client deployment (coming soon)
|
* Handle route and DNS settings like wg-quick does
|
||||||
|
* ~~REST API for management and client deployment~~ (coming soon)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
You can configure WireGuard Portal using a yaml configuration file.
|
You can configure WireGuard Portal using a yaml configuration file.
|
||||||
The filepath of the yaml configuration file defaults to **config.yml** in the working directory of the executable.
|
The filepath of the yaml configuration file defaults to **config.yml** in the working directory of the executable.
|
||||||
@ -55,94 +60,129 @@ The following configuration options are available:
|
|||||||
| log_level | advanced | warn | The loglevel, can be one of: trace, debug, info, warn, error. |
|
| log_level | advanced | warn | The loglevel, can be one of: trace, debug, info, warn, error. |
|
||||||
| log_pretty | advanced | false | Uses pretty, colorized log messages. |
|
| log_pretty | advanced | false | Uses pretty, colorized log messages. |
|
||||||
| log_json | advanced | false | Logs in JSON format. |
|
| log_json | advanced | false | Logs in JSON format. |
|
||||||
| ldap_sync_interval | advanced | 15m | |
|
| ldap_sync_interval | advanced | 15m | The time interval after which users will be synchronized from LDAP. |
|
||||||
| start_listen_port | advanced | 51820 | |
|
| start_listen_port | advanced | 51820 | The first port number that will be used as listening port for new interfaces. |
|
||||||
| start_cidr_v4 | advanced | 10.11.12.0/24 | |
|
| start_cidr_v4 | advanced | 10.11.12.0/24 | The first IPv4 subnet that will be used for new interfaces. |
|
||||||
| start_cidr_v6 | advanced | fdfd:d3ad:c0de:1234::0/64 | |
|
| start_cidr_v6 | advanced | fdfd:d3ad:c0de:1234::0/64 | The first IPv6 subnet that will be used for new interfaces. |
|
||||||
| use_ip_v6 | advanced | true | |
|
| use_ip_v6 | advanced | true | Enable IPv6 support. |
|
||||||
| config_storage_path | advanced | | |
|
| config_storage_path | advanced | | If a wg-quick style configuration should be stored to the filesystem, specify a storage directory. |
|
||||||
| expiry_check_interval | advanced | 15m | |
|
| expiry_check_interval | advanced | 15m | The interval after which existing peers will be checked if they expired. |
|
||||||
| rule_prio_offset | advanced | 20000 | |
|
| rule_prio_offset | advanced | 20000 | The default offset for ip route rule priorities. |
|
||||||
| route_table_offset | advanced | 20000 | |
|
| route_table_offset | advanced | 20000 | The default offset for ip route table id's. |
|
||||||
| use_ping_checks | statistics | true | |
|
| use_ping_checks | statistics | true | If enabled, peers will be pinged periodically to check if they are still connected. |
|
||||||
| ping_check_workers | statistics | 10 | |
|
| ping_check_workers | statistics | 10 | Number of parallel ping checks that will be executed. |
|
||||||
| ping_unprivileged | statistics | false | |
|
| ping_unprivileged | statistics | false | If set to false, the ping checks will run without root permissions (BETA). |
|
||||||
| ping_check_interval | statistics | 1m | |
|
| ping_check_interval | statistics | 1m | The interval time between two ping check runs. |
|
||||||
| data_collection_interval | statistics | 10m | |
|
| data_collection_interval | statistics | 10m | The interval between the data collection cycles. |
|
||||||
| collect_interface_data | statistics | true | |
|
| collect_interface_data | statistics | true | A flag to enable interface data collection like bytes sent and received. |
|
||||||
| collect_peer_data | statistics | true | |
|
| collect_peer_data | statistics | true | A flag to enable peer data collection like bytes sent and received, last handshake and remote endpoint address. |
|
||||||
| collect_audit_data | statistics | true | |
|
| collect_audit_data | statistics | true | If enabled, some events, like portal logins, will be logged to the database. |
|
||||||
| host | mail | 127.0.0.1 | |
|
| host | mail | 127.0.0.1 | The mail-server address. |
|
||||||
| port | mail | 25 | |
|
| port | mail | 25 | The mail-server SMTP port. |
|
||||||
| encryption | mail | none | |
|
| encryption | mail | none | SMTP encryption type, allowed values: none, tls, starttls. |
|
||||||
| cert_validation | mail | false | |
|
| cert_validation | mail | false | Validate the mail server certificate (if encryption tls is used). |
|
||||||
| username | mail | | |
|
| username | mail | | The SMTP user name. |
|
||||||
| password | mail | | |
|
| password | mail | | The SMTP password. |
|
||||||
| auth_type | mail | plain | |
|
| auth_type | mail | plain | SMTP authentication type, allowed values: plain, login, crammd5. |
|
||||||
| from | mail | Wireguard Portal <noreply@wireguard.local> | |
|
| from | mail | Wireguard Portal <noreply@wireguard.local> | The address that is used to send mails. |
|
||||||
| link_only | mail | false | |
|
| link_only | mail | false | Only send links to WireGuard Portal instead of the full configuration. |
|
||||||
| callback_url_prefix | auth | /api/v0 | |
|
| callback_url_prefix | auth | /api/v0 | OAuth callback URL prefix. The full callback URL will look like: https://wg.portal.local/callback_url_prefix/provider_name/callback |
|
||||||
| oidc | auth | Empty Array - no providers configured | |
|
| oidc | auth | Empty Array - no providers configured | A list of OpenID Connect providers. See auth/oidc properties to setup a new provider. |
|
||||||
| oauth | auth | Empty Array - no providers configured | |
|
| oauth | auth | Empty Array - no providers configured | A list of plain OAuth providers. See auth/oauth properties to setup a new provider. |
|
||||||
| ldap | auth | Empty Array - no providers configured | |
|
| ldap | auth | Empty Array - no providers configured | A list of LDAP providers. See auth/ldap properties to setup a new provider. |
|
||||||
| provider_name | auth/oidc | | |
|
| provider_name | auth/oidc | | A unique provider name. This name must be unique throughout all authentication providers (even other types). |
|
||||||
| display_name | auth/oidc | | |
|
| display_name | auth/oidc | | The display name is shown at the login page (the login button). |
|
||||||
| base_url | auth/oidc | | |
|
| base_url | auth/oidc | | The base_url is the URL identifier for the service. For example: "https://accounts.google.com". |
|
||||||
| client_id | auth/oidc | | |
|
| client_id | auth/oidc | | The OAuth client id. |
|
||||||
| client_secret | auth/oidc | | |
|
| client_secret | auth/oidc | | The OAuth client secret. |
|
||||||
| extra_scopes | auth/oidc | | |
|
| extra_scopes | auth/oidc | | Extra scopes that should be used in the OpenID Connect authentication flow. |
|
||||||
| field_map | auth/oidc | | |
|
| field_map | auth/oidc | | Mapping of user fields. Internal fields: user_identifier, email, firstname, lastname, phone, department and is_admin. |
|
||||||
| registration_enabled | auth/oidc | | |
|
| registration_enabled | auth/oidc | | If registration is enabled, new user accounts will created in WireGuard Portal. |
|
||||||
| provider_name | auth/oidc | | |
|
| provider_name | auth/oauth | | A unique provider name. This name must be unique throughout all authentication providers (even other types). |
|
||||||
| display_name | auth/oauth | | |
|
| display_name | auth/oauth | | The display name is shown at the login page (the login button). |
|
||||||
| base_url | auth/oauth | | |
|
| base_url | auth/oauth | | The base_url is the URL identifier for the service. For example: "https://accounts.google.com". |
|
||||||
| client_id | auth/oauth | | |
|
| client_id | auth/oauth | | The OAuth client id. |
|
||||||
| client_secret | auth/oauth | | |
|
| client_secret | auth/oauth | | The OAuth client secret. |
|
||||||
| auth_url | auth/oauth | | |
|
| auth_url | auth/oauth | | The URL for the authentication endpoint. |
|
||||||
| token_url | auth/oauth | | |
|
| token_url | auth/oauth | | The URL for the token endpoint. |
|
||||||
| redirect_url | auth/oauth | | |
|
| redirect_url | auth/oauth | | The redirect URL. |
|
||||||
| user_info_url | auth/oauth | | |
|
| user_info_url | auth/oauth | | The URL for the user information endpoint. |
|
||||||
| scopes | auth/oauth | | |
|
| scopes | auth/oauth | | OAuth scopes. |
|
||||||
| field_map | auth/oauth | | |
|
| field_map | auth/oauth | | Mapping of user fields. Internal fields: user_identifier, email, firstname, lastname, phone, department and is_admin. |
|
||||||
| registration_enabled | auth/oauth | | |
|
| registration_enabled | auth/oauth | | If registration is enabled, new user accounts will created in WireGuard Portal. |
|
||||||
| url | auth/ldap | | |
|
| url | auth/ldap | | The LDAP server url. For example: ldap://srv-ad01.company.local:389 |
|
||||||
| start_tls | auth/ldap | | |
|
| start_tls | auth/ldap | | Use STARTTLS to encrypt LDAP requests. |
|
||||||
| cert_validation | auth/ldap | | |
|
| cert_validation | auth/ldap | | Validate the LDAP server certificate. |
|
||||||
| tls_certificate_path | auth/ldap | | |
|
| tls_certificate_path | auth/ldap | | A path to the TLS certificate. |
|
||||||
| tls_key_path | auth/ldap | | |
|
| tls_key_path | auth/ldap | | A path to the TLS key. |
|
||||||
| base_dn | auth/ldap | | |
|
| base_dn | auth/ldap | | The base DN for searching users. For example: DC=COMPANY,DC=LOCAL |
|
||||||
| bind_user | auth/ldap | | |
|
| bind_user | auth/ldap | | The bind user. For example: company\\ldap_wireguard |
|
||||||
| bind_pass | auth/ldap | | |
|
| bind_pass | auth/ldap | | The bind password. |
|
||||||
| field_map | auth/ldap | | |
|
| field_map | auth/ldap | | Mapping of user fields. Internal fields: user_identifier, email, firstname, lastname, phone, department and memberof. |
|
||||||
| login_filter | auth/ldap | | |
|
| login_filter | auth/ldap | | LDAP filters for users that should be allowed to log in. {{login_identifier}} will be replaced with the login username. |
|
||||||
| admin_group | auth/ldap | | |
|
| admin_group | auth/ldap | | Users in this group are marked as administrators. |
|
||||||
| synchronize | auth/ldap | | |
|
| synchronize | auth/ldap | | Periodically synchronize users (name, department, phone, status, ...) to the WireGuard Portal database. |
|
||||||
| disable_missing | auth/ldap | | |
|
| disable_missing | auth/ldap | | If synchronization is enabled, missing LDAP users will be disabled in WireGuard Portal. |
|
||||||
| sync_filter | auth/ldap | | |
|
| sync_filter | auth/ldap | | LDAP filters for users that should be synchronized to WireGuard Portal. |
|
||||||
| registration_enabled | auth/ldap | | |
|
| registration_enabled | auth/ldap | | If registration is enabled, new user accounts will created in WireGuard Portal. |
|
||||||
| debug | database | false | |
|
| debug | database | false | Debug database statements (log each statement). |
|
||||||
| slow_query_threshold | database | | |
|
| slow_query_threshold | database | | A threshold for slow database queries. If the threshold is exceeded, a warning message will be logged. |
|
||||||
| type | database | sqlite | |
|
| type | database | sqlite | The database type. Allowed values: sqlite, mssql, mysql or postgres. |
|
||||||
| dsn | database | sqlite.db | |
|
| dsn | database | sqlite.db | The database DSN. For example: user:pass@tcp(1.2.3.4:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local |
|
||||||
| request_logging | web | false | |
|
| request_logging | web | false | Log all HTTP requests. |
|
||||||
| external_url | web | http://localhost:8888 | |
|
| external_url | web | http://localhost:8888 | The URL where a client can access WireGuard Portal. |
|
||||||
| listening_address | web | :8888 | |
|
| listening_address | web | :8888 | The listening port of the web server. |
|
||||||
| session_identifier | web | wgPortalSession | |
|
| session_identifier | web | wgPortalSession | The session identifier for the web frontend. |
|
||||||
| session_secret | web | very_secret | |
|
| session_secret | web | very_secret | The session secret for the web frontend. |
|
||||||
| csrf_secret | web | extremely_secret | |
|
| csrf_secret | web | extremely_secret | The CSRF secret. |
|
||||||
| site_title | web | WireGuard Portal | |
|
| site_title | web | WireGuard Portal | The title that is shown in the web frontend. |
|
||||||
| site_company_name | web | WireGuard Portal | |
|
| site_company_name | web | WireGuard Portal | The company name that is shown at the bottom of the web frontend. |
|
||||||
|
|
||||||
|
|
||||||
|
## Upgrading from V1
|
||||||
|
|
||||||
|
> :warning: Before upgrading from V1, make sure that you have a backup of your currently working configuration files and database!
|
||||||
|
|
||||||
|
To start the upgrade process, start the wg-portal binary with the **-migrateFrom** parameter.
|
||||||
|
The configuration (config.yml) for WireGuard Portal must be updated and valid before starting the upgrade.
|
||||||
|
|
||||||
|
To upgrade from a previous SQLite database, start wg-portal like:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
./wg-portal-amd64 -migrateFrom=old_wg_portal.db
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also specify the database type using the parameter **-migrateFromType**, supported types: mysql, mssql, postgres or sqlite.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
./wg-portal-amd64 -migrateFromType=mysql -migrateFrom=user:pass@tcp(1.2.3.4:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
|
||||||
|
```
|
||||||
|
|
||||||
|
The upgrade will transform the old, existing database and store the values in the new database specified in config.yml.
|
||||||
|
Ensure that the new database does not contain any data!
|
||||||
|
|
||||||
|
|
||||||
|
## V2 TODOs
|
||||||
|
* Public REST API
|
||||||
|
* Translations
|
||||||
|
* Documentation
|
||||||
|
* Audit UI
|
||||||
|
|
||||||
|
|
||||||
## What is out of scope
|
## What is out of scope
|
||||||
* Generation or application of any `iptables` or `nftables` rules.
|
* Automatic generation or application of any `iptables` or `nftables` rules.
|
||||||
* Setting up or changing IP-addresses of the WireGuard interface on operating systems other than linux.
|
* Support for operating systems other than linux.
|
||||||
* Importing private keys of an existing WireGuard setup.
|
* Automatic import of private keys of an existing WireGuard setup.
|
||||||
|
|
||||||
|
|
||||||
## Application stack
|
## Application stack
|
||||||
|
|
||||||
* [Gin, HTTP web framework written in Go](https://github.com/gin-gonic/gin)
|
* [wgctrl-go](https://github.com/WireGuard/wgctrl-go) and [netlink](https://github.com/vishvananda/netlink) for interface handling
|
||||||
* [Bootstrap, for the HTML templates](https://getbootstrap.com/)
|
* [Gin](https://github.com/gin-gonic/gin), HTTP web framework written in Go
|
||||||
* [Vue.JS, for the frontend](https://vuejs.org/)
|
* [Bootstrap](https://getbootstrap.com/), for the HTML templates
|
||||||
|
* [Vue.JS](https://vuejs.org/), for the frontend
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
@ -28,7 +28,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
ctx := internal.SignalAwareContext(context.Background(), syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
|
ctx := internal.SignalAwareContext(context.Background(), syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
logrus.Infof("Starting WireGuard Portal...")
|
logrus.Infof("Starting WireGuard Portal V2...")
|
||||||
|
logrus.Infof("WireGuard Portal version: %s", internal.Version)
|
||||||
|
|
||||||
cfg, err := config.GetConfig()
|
cfg, err := config.GetConfig()
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
@ -77,7 +78,7 @@ func main() {
|
|||||||
statisticsCollector, err := wireguard.NewStatisticsCollector(cfg, database, wireGuard)
|
statisticsCollector, err := wireguard.NewStatisticsCollector(cfg, database, wireGuard)
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
|
|
||||||
cfgFileManager, err := configfile.NewConfigFileManager(cfg, database, database, cfgFileSystem)
|
cfgFileManager, err := configfile.NewConfigFileManager(cfg, eventBus, database, database, cfgFileSystem)
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
|
|
||||||
mailManager, err := mail.NewMailManager(cfg, mailer, cfgFileManager, database, database)
|
mailManager, err := mail.NewMailManager(cfg, mailer, cfgFileManager, database, database)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
version: '3.6'
|
version: '3.6'
|
||||||
services:
|
services:
|
||||||
wg-portal:
|
wg-portal:
|
||||||
image: h44z/wg-portal:1.0.16
|
image: h44z/wg-portal:2.0.0-alpha1
|
||||||
container_name: wg-portal
|
container_name: wg-portal
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
logging:
|
logging:
|
||||||
@ -16,4 +16,4 @@ services:
|
|||||||
- /etc/wireguard:/etc/wireguard
|
- /etc/wireguard:/etc/wireguard
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
environment:
|
environment:
|
||||||
- EXTERNAL_URL=http://localhost:8123
|
- EXTERNAL_URL=http://localhost:8888
|
||||||
|
@ -33,9 +33,9 @@ const title = computed(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (selectedInterface.value) {
|
if (selectedInterface.value) {
|
||||||
return t("interfaces.interface.edit") + ": " + selectedInterface.value.Identifier
|
return t("modals.interface-edit.headline-edit") + " " + selectedInterface.value.Identifier
|
||||||
}
|
}
|
||||||
return t("interfaces.interface.new")
|
return t("modals.interface-edit.headline-new")
|
||||||
})
|
})
|
||||||
|
|
||||||
const formData = ref(freshInterface())
|
const formData = ref(freshInterface())
|
||||||
@ -291,134 +291,135 @@ async function del() {
|
|||||||
<template #default>
|
<template #default>
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" data-bs-toggle="tab" href="#interface">Interface</a>
|
<a class="nav-link active" data-bs-toggle="tab" href="#interface">{{ $t('modals.interface-edit.tab-interface') }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="formData.Mode==='server'" class="nav-item">
|
<li v-if="formData.Mode==='server'" class="nav-item">
|
||||||
<a class="nav-link" data-bs-toggle="tab" href="#peerdefaults">Peer Defaults</a>
|
<a class="nav-link" data-bs-toggle="tab" href="#peerdefaults">{{ $t('modals.interface-edit.tab-peerdef') }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div id="interfaceTabs" class="tab-content">
|
<div id="interfaceTabs" class="tab-content">
|
||||||
<div id="interface" class="tab-pane fade active show">
|
<div id="interface" class="tab-pane fade active show">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend class="mt-4">General</legend>
|
<legend class="mt-4">{{ $t('modals.interface-edit.header-general') }}</legend>
|
||||||
<div v-if="props.interfaceId==='#NEW#'" class="form-group">
|
<div v-if="props.interfaceId==='#NEW#'" class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.identifier') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.identifier.label') }}</label>
|
||||||
<input v-model="formData.Identifier" class="form-control" placeholder="The device identifier" type="text">
|
<input v-model="formData.Identifier" class="form-control" :placeholder="$t('modals.interface-edit.identifier.placeholder')" type="text">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.displayname') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.mode.label') }}</label>
|
||||||
<select v-model="formData.Mode" class="form-select">
|
<select v-model="formData.Mode" class="form-select">
|
||||||
<option value="server">Server Mode</option>
|
<option value="server">{{ $t('modals.interface-edit.mode.server') }}</option>
|
||||||
<option value="client">Client Mode</option>
|
<option value="client">{{ $t('modals.interface-edit.mode.client') }}</option>
|
||||||
<option value="any">Custom Mode</option>
|
<option value="any">{{ $t('modals.interface-edit.mode.any') }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.displayname') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.display-name.label') }}</label>
|
||||||
<input v-model="formData.DisplayName" class="form-control" placeholder="A descriptive name of the interface" type="text">
|
<input v-model="formData.DisplayName" class="form-control" :placeholder="$t('modals.interface-edit.display-name.placeholder')" type="text">
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend class="mt-4">Cryptography</legend>
|
<legend class="mt-4">{{ $t('modals.interface-edit.header-crypto') }}</legend>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.privatekey') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.private-key.label') }}</label>
|
||||||
<input v-model="formData.PrivateKey" class="form-control" placeholder="The private key" required type="email">
|
<input v-model="formData.PrivateKey" class="form-control" :placeholder="$t('modals.interface-edit.private-key.placeholder')" required type="email">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.publickey') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.public-key.label') }}</label>
|
||||||
<input v-model="formData.PublicKey" class="form-control" placeholder="The public key" required type="email">
|
<input v-model="formData.PublicKey" class="form-control" :placeholder="$t('modals.interface-edit.public-key.placeholder')" required type="email">
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend class="mt-4">Networking</legend>
|
<legend class="mt-4">{{ $t('modals.interface-edit.header-network') }}</legend>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.ips') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.ip.label') }}</label>
|
||||||
<vue3-tags-input class="form-control" :tags="formData.Addresses"
|
<vue3-tags-input class="form-control" :tags="formData.Addresses"
|
||||||
placeholder="IP Addresses (CIDR format)"
|
:placeholder="$t('modals.interface-edit.ip.placeholder')"
|
||||||
:add-tag-on-keys="[13, 188, 32, 9]"
|
:add-tag-on-keys="[13, 188, 32, 9]"
|
||||||
:validate="validateCIDR"
|
:validate="validateCIDR"
|
||||||
@on-tags-changed="handleChangeAddresses"/>
|
@on-tags-changed="handleChangeAddresses"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="formData.Mode==='server'" class="form-group">
|
<div v-if="formData.Mode==='server'" class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.listenport') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.listen-port.label') }}</label>
|
||||||
<input v-model="formData.ListenPort" class="form-control" placeholder="Listen Port" type="number">
|
<input v-model="formData.ListenPort" class="form-control" :placeholder="$t('modals.interface-edit.listen-port.placeholder')" type="number">
|
||||||
</div>
|
</div>
|
||||||
<div v-if="formData.Mode!=='server'" class="form-group">
|
<div v-if="formData.Mode!=='server'" class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.dns') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.dns.label') }}</label>
|
||||||
<vue3-tags-input class="form-control" :tags="formData.Dns"
|
<vue3-tags-input class="form-control" :tags="formData.Dns"
|
||||||
placeholder="DNS Servers"
|
:placeholder="$t('modals.interface-edit.dns.placeholder')"
|
||||||
:add-tag-on-keys="[13, 188, 32, 9]"
|
:add-tag-on-keys="[13, 188, 32, 9]"
|
||||||
:validate="validateIP"
|
:validate="validateIP"
|
||||||
@on-tags-changed="handleChangeDns"/>
|
@on-tags-changed="handleChangeDns"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="formData.Mode!=='server'" class="form-group">
|
<div v-if="formData.Mode!=='server'" class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.dnssearch') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.dns-search.label') }}</label>
|
||||||
<vue3-tags-input class="form-control" :tags="formData.DnsSearch"
|
<vue3-tags-input class="form-control" :tags="formData.DnsSearch"
|
||||||
placeholder="DNS Search prefixes"
|
:placeholder="$t('modals.interface-edit.dns-search.placeholder')"
|
||||||
:add-tag-on-keys="[13, 188, 32, 9]"
|
:add-tag-on-keys="[13, 188, 32, 9]"
|
||||||
:validate="validateDomain"
|
:validate="validateDomain"
|
||||||
@on-tags-changed="handleChangeDnsSearch"/>
|
@on-tags-changed="handleChangeDnsSearch"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.mtu') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.mtu.label') }}</label>
|
||||||
<input v-model="formData.Mtu" class="form-control" placeholder="Client MTU (0 = default)" type="number">
|
<input v-model="formData.Mtu" class="form-control" :placeholder="$t('modals.interface-edit.mtu.placeholder')" type="number">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.firewallmark') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.firewall-mark.label') }}</label>
|
||||||
<input v-model="formData.FirewallMark" class="form-control" placeholder="Firewall Mark (0 = default)" type="number">
|
<input v-model="formData.FirewallMark" class="form-control" :placeholder="$t('modals.interface-edit.firewall-mark.placeholder')" type="number">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.routingtable') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.routing-table.label') }}</label>
|
||||||
<input v-model="formData.RoutingTable" class="form-control" placeholder="Routing Table (0 = default)" type="number">
|
<input v-model="formData.RoutingTable" aria-describedby="routingTableHelp" class="form-control" :placeholder="$t('modals.interface-edit.routing-table.placeholder')" type="text">
|
||||||
|
<small id="routingTableHelp" class="form-text text-muted">{{ $t('modals.interface-edit.routing-table.description') }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend class="mt-4">Hooks</legend>
|
<legend class="mt-4">{{ $t('modals.interface-edit.header-hooks') }}</legend>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.preup') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.pre-up.label') }}</label>
|
||||||
<textarea v-model="formData.PreUp" class="form-control" rows="2"></textarea>
|
<textarea v-model="formData.PreUp" class="form-control" rows="2" :placeholder="$t('modals.interface-edit.pre-up.placeholder')"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.postup') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.post-up.label') }}</label>
|
||||||
<textarea v-model="formData.PostUp" class="form-control" rows="2"></textarea>
|
<textarea v-model="formData.PostUp" class="form-control" rows="2" :placeholder="$t('modals.interface-edit.post-up.placeholder')"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.predown') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.pre-down.label') }}</label>
|
||||||
<textarea v-model="formData.PreDown" class="form-control" rows="2"></textarea>
|
<textarea v-model="formData.PreDown" class="form-control" rows="2" :placeholder="$t('modals.interface-edit.pre-down.placeholder')"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.postdown') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.post-down.label') }}</label>
|
||||||
<textarea v-model="formData.PostDown" class="form-control" rows="2"></textarea>
|
<textarea v-model="formData.PostDown" class="form-control" rows="2" :placeholder="$t('modals.interface-edit.post-down.placeholder')"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend class="mt-4">State</legend>
|
<legend class="mt-4">{{ $t('modals.interface-edit.header-state') }}</legend>
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input v-model="formData.Disabled" class="form-check-input" type="checkbox">
|
<input v-model="formData.Disabled" class="form-check-input" type="checkbox">
|
||||||
<label class="form-check-label" >Disabled</label>
|
<label class="form-check-label">{{ $t('modals.interface-edit.disabled.label') }}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input v-model="formData.SaveConfig" checked="" class="form-check-input" type="checkbox">
|
<input v-model="formData.SaveConfig" checked="" class="form-check-input" type="checkbox">
|
||||||
<label class="form-check-label">Save Config to File</label>
|
<label class="form-check-label">{{ $t('modals.interface-edit.save-config.label') }}</label>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div id="peerdefaults" class="tab-pane fade">
|
<div id="peerdefaults" class="tab-pane fade">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend class="mt-4">Networking</legend>
|
<legend class="mt-4">{{ $t('modals.interface-edit.header-network') }}</legend>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.endpoint') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.endpoint') }}</label>
|
||||||
<input v-model="formData.PeerDefEndpoint" class="form-control" placeholder="Endpoint Addresses" type="text">
|
<input v-model="formData.PeerDefEndpoint" class="form-control" placeholder="Endpoint Addresses" type="text">
|
||||||
<small class="form-text text-muted">The endpoint address that peers will connect to.</small>
|
<small class="form-text text-muted">The endpoint address that peers will connect to.</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.networks') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.networks') }}</label>
|
||||||
<vue3-tags-input class="form-control" :tags="formData.PeerDefNetwork"
|
<vue3-tags-input class="form-control" :tags="formData.PeerDefNetwork"
|
||||||
placeholder="Network Addresses"
|
placeholder="Network Addresses"
|
||||||
:add-tag-on-keys="[13, 188, 32, 9]"
|
:add-tag-on-keys="[13, 188, 32, 9]"
|
||||||
@ -427,7 +428,7 @@ async function del() {
|
|||||||
<small class="form-text text-muted">Peers will get IP addresses from those subnets.</small>
|
<small class="form-text text-muted">Peers will get IP addresses from those subnets.</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.allowedips') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.allowedips') }}</label>
|
||||||
<vue3-tags-input class="form-control" :tags="formData.PeerDefAllowedIPs"
|
<vue3-tags-input class="form-control" :tags="formData.PeerDefAllowedIPs"
|
||||||
placeholder="Default Allowed IP Addresses"
|
placeholder="Default Allowed IP Addresses"
|
||||||
:add-tag-on-keys="[13, 188, 32, 9]"
|
:add-tag-on-keys="[13, 188, 32, 9]"
|
||||||
@ -435,7 +436,7 @@ async function del() {
|
|||||||
@on-tags-changed="handleChangePeerDefAllowedIPs"/>
|
@on-tags-changed="handleChangePeerDefAllowedIPs"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.dns') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.dns') }}</label>
|
||||||
<vue3-tags-input class="form-control" :tags="formData.PeerDefDns"
|
<vue3-tags-input class="form-control" :tags="formData.PeerDefDns"
|
||||||
placeholder="DNS Servers"
|
placeholder="DNS Servers"
|
||||||
:add-tag-on-keys="[13, 188, 32, 9]"
|
:add-tag-on-keys="[13, 188, 32, 9]"
|
||||||
@ -443,7 +444,7 @@ async function del() {
|
|||||||
@on-tags-changed="handleChangePeerDefDns"/>
|
@on-tags-changed="handleChangePeerDefDns"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.dnssearch') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.dnssearch') }}</label>
|
||||||
<vue3-tags-input class="form-control" :tags="formData.PeerDefDnsSearch"
|
<vue3-tags-input class="form-control" :tags="formData.PeerDefDnsSearch"
|
||||||
placeholder="DNS Search prefix"
|
placeholder="DNS Search prefix"
|
||||||
:add-tag-on-keys="[13, 188, 32, 9]"
|
:add-tag-on-keys="[13, 188, 32, 9]"
|
||||||
@ -452,41 +453,41 @@ async function del() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.mtu') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.mtu') }}</label>
|
||||||
<input v-model="formData.PeerDefMtu" class="form-control" placeholder="Client MTU (0 = default)" type="number">
|
<input v-model="formData.PeerDefMtu" class="form-control" placeholder="Client MTU (0 = default)" type="number">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.firewallmark') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.firewallmark') }}</label>
|
||||||
<input v-model="formData.PeerDefFirewallMark" class="form-control" placeholder="Firewall Mark (0 = default)" type="number">
|
<input v-model="formData.PeerDefFirewallMark" class="form-control" placeholder="Firewall Mark (0 = default)" type="number">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.routingtable') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.routingtable') }}</label>
|
||||||
<input v-model="formData.PeerDefRoutingTable" class="form-control" placeholder="Routing Table (0 = default)" type="number">
|
<input v-model="formData.PeerDefRoutingTable" class="form-control" placeholder="Routing Table (0 = default)" type="number">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.keepalive') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.keepalive') }}</label>
|
||||||
<input v-model="formData.PeerDefPersistentKeepalive" class="form-control" placeholder="Persistent Keepalive (0 = default)" type="number">
|
<input v-model="formData.PeerDefPersistentKeepalive" class="form-control" placeholder="Persistent Keepalive (0 = default)" type="number">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend class="mt-4">Hooks</legend>
|
<legend class="mt-4">{{ $t('modals.interface-edit.header-peer-hooks') }}</legend>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.preup') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.preup') }}</label>
|
||||||
<textarea v-model="formData.PeerDefPreUp" class="form-control" rows="2"></textarea>
|
<textarea v-model="formData.PeerDefPreUp" class="form-control" rows="2"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.postup') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.postup') }}</label>
|
||||||
<textarea v-model="formData.PeerDefPostUp" class="form-control" rows="2"></textarea>
|
<textarea v-model="formData.PeerDefPostUp" class="form-control" rows="2"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.predown') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.predown') }}</label>
|
||||||
<textarea v-model="formData.PeerDefPreDown" class="form-control" rows="2"></textarea>
|
<textarea v-model="formData.PeerDefPreDown" class="form-control" rows="2"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label mt-4">{{ $t('modals.interfaceedit.defaults.postdown') }}</label>
|
<label class="form-label mt-4">{{ $t('modals.interface-edit.defaults.postdown') }}</label>
|
||||||
<textarea v-model="formData.PeerDefPostDown" class="form-control" rows="2"></textarea>
|
<textarea v-model="formData.PeerDefPostDown" class="form-control" rows="2"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@ -499,10 +500,10 @@ async function del() {
|
|||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="flex-fill text-start">
|
<div class="flex-fill text-start">
|
||||||
<button v-if="props.interfaceId!=='#NEW#'" class="btn btn-danger me-1" type="button" @click.prevent="del">Delete</button>
|
<button v-if="props.interfaceId!=='#NEW#'" class="btn btn-danger me-1" type="button" @click.prevent="del">{{ $t('general.delete') }}</button>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save">Save</button>
|
<button class="btn btn-primary me-1" type="button" @click.prevent="save">{{ $t('general.save') }}</button>
|
||||||
<button class="btn btn-secondary" type="button" @click.prevent="close">Discard</button>
|
<button class="btn btn-secondary" type="button" @click.prevent="close">{{ $t('general.close') }}</button>
|
||||||
</template>
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
@ -243,7 +243,89 @@
|
|||||||
"headline": "Config for Interface:"
|
"headline": "Config for Interface:"
|
||||||
},
|
},
|
||||||
"interface-edit": {
|
"interface-edit": {
|
||||||
"privatekey": "Private Key"
|
"headline-edit": "Edit Interface:",
|
||||||
|
"headline-new": "New Interface",
|
||||||
|
"tab-interface": "Interface",
|
||||||
|
"tab-peerdef": "Peer Defaults",
|
||||||
|
"header-general": "General",
|
||||||
|
"header-network": "Network",
|
||||||
|
"header-crypto": "Cryptography",
|
||||||
|
"header-hooks": "Interface Hooks",
|
||||||
|
"header-peer-hooks": "Hooks",
|
||||||
|
"header-state": "State",
|
||||||
|
"identifier": {
|
||||||
|
"label": "Identifier",
|
||||||
|
"placeholder": "The unique interface identifier"
|
||||||
|
},
|
||||||
|
"mode": {
|
||||||
|
"label": "Interface Mode",
|
||||||
|
"server": "Server Mode",
|
||||||
|
"client": "Client Mode",
|
||||||
|
"any": "Unknown Mode"
|
||||||
|
},
|
||||||
|
"display-name": {
|
||||||
|
"label": "Display Name",
|
||||||
|
"placeholder": "The descriptive name for the interface"
|
||||||
|
},
|
||||||
|
"private-key": {
|
||||||
|
"label": "Private Key",
|
||||||
|
"placeholder": "The private key"
|
||||||
|
},
|
||||||
|
"public-key": {
|
||||||
|
"label": "Public Key",
|
||||||
|
"placeholder": "The public key"
|
||||||
|
},
|
||||||
|
"ip": {
|
||||||
|
"label": "IP Addresses",
|
||||||
|
"placeholder": "IP Addresses (CIDR format)"
|
||||||
|
},
|
||||||
|
"listen-port": {
|
||||||
|
"label": "Listen Port",
|
||||||
|
"placeholder": "The listening port"
|
||||||
|
},
|
||||||
|
"dns": {
|
||||||
|
"label": "DNS Server",
|
||||||
|
"placeholder": "The DNS servers that should be used"
|
||||||
|
},
|
||||||
|
"dns-search": {
|
||||||
|
"label": "DNS Search Domains",
|
||||||
|
"placeholder": "DNS search prefixes"
|
||||||
|
},
|
||||||
|
"mtu": {
|
||||||
|
"label": "MTU",
|
||||||
|
"placeholder": "The interface MTU (0 = keep default)"
|
||||||
|
},
|
||||||
|
"firewall-mark": {
|
||||||
|
"label": "Firewall Mark",
|
||||||
|
"placeholder": "Firewall mark that is applied to outgoing traffic. (0 = automatic)"
|
||||||
|
},
|
||||||
|
"routing-table": {
|
||||||
|
"label": "Routing Table",
|
||||||
|
"placeholder": "The routing table ID",
|
||||||
|
"description": "Special cases: off = do not manage routes, 0 = automatic"
|
||||||
|
},
|
||||||
|
"pre-up": {
|
||||||
|
"label": "Pre-Up",
|
||||||
|
"placeholder": "One or multiple bash commands"
|
||||||
|
},
|
||||||
|
"post-up": {
|
||||||
|
"label": "Post-Up",
|
||||||
|
"placeholder": "One or multiple bash commands"
|
||||||
|
},
|
||||||
|
"pre-down": {
|
||||||
|
"label": "Pre-Down",
|
||||||
|
"placeholder": "One or multiple bash commands"
|
||||||
|
},
|
||||||
|
"post-down": {
|
||||||
|
"label": "Post-Down",
|
||||||
|
"placeholder": "One or multiple bash commands"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"label": "Interface Disabled"
|
||||||
|
},
|
||||||
|
"save-config": {
|
||||||
|
"label": "Automatically save wg-quick config"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"peer-view": {
|
"peer-view": {
|
||||||
"headline-peer": "Peer:",
|
"headline-peer": "Peer:",
|
||||||
|
12
go.mod
12
go.mod
@ -7,7 +7,7 @@ require (
|
|||||||
github.com/gin-contrib/cors v1.4.0
|
github.com/gin-contrib/cors v1.4.0
|
||||||
github.com/gin-contrib/sessions v0.0.5
|
github.com/gin-contrib/sessions v0.0.5
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/glebarez/sqlite v1.8.0
|
github.com/glebarez/sqlite v1.9.0
|
||||||
github.com/go-ldap/ldap/v3 v3.4.5
|
github.com/go-ldap/ldap/v3 v3.4.5
|
||||||
github.com/prometheus-community/pro-bing v0.3.0
|
github.com/prometheus-community/pro-bing v0.3.0
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
@ -18,9 +18,10 @@ require (
|
|||||||
github.com/vardius/message-bus v1.1.5
|
github.com/vardius/message-bus v1.1.5
|
||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.1.0
|
||||||
github.com/xhit/go-simple-mail/v2 v2.15.0
|
github.com/xhit/go-simple-mail/v2 v2.15.0
|
||||||
github.com/yeqown/go-qrcode/v2 v2.2.1
|
github.com/yeqown/go-qrcode/v2 v2.2.2
|
||||||
golang.org/x/crypto v0.11.0
|
golang.org/x/crypto v0.11.0
|
||||||
golang.org/x/oauth2 v0.10.0
|
golang.org/x/oauth2 v0.10.0
|
||||||
|
golang.org/x/sys v0.10.0
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gorm.io/driver/mysql v1.5.1
|
gorm.io/driver/mysql v1.5.1
|
||||||
@ -39,7 +40,7 @@ require (
|
|||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/glebarez/go-sqlite v1.21.1 // indirect
|
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||||
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
|
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
@ -91,16 +92,15 @@ require (
|
|||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/net v0.12.0 // indirect
|
golang.org/x/net v0.12.0 // indirect
|
||||||
golang.org/x/sync v0.3.0 // indirect
|
golang.org/x/sync v0.3.0 // indirect
|
||||||
golang.org/x/sys v0.10.0 // indirect
|
|
||||||
golang.org/x/text v0.11.0 // indirect
|
golang.org/x/text v0.11.0 // indirect
|
||||||
golang.org/x/tools v0.9.3 // indirect
|
golang.org/x/tools v0.9.3 // indirect
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect
|
golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/protobuf v1.31.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
modernc.org/libc v1.22.3 // indirect
|
modernc.org/libc v1.22.5 // indirect
|
||||||
modernc.org/mathutil v1.5.0 // indirect
|
modernc.org/mathutil v1.5.0 // indirect
|
||||||
modernc.org/memory v1.5.0 // indirect
|
modernc.org/memory v1.5.0 // indirect
|
||||||
modernc.org/sqlite v1.21.1 // indirect
|
modernc.org/sqlite v1.23.1 // indirect
|
||||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
20
go.sum
20
go.sum
@ -45,10 +45,10 @@ github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6
|
|||||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||||
github.com/glebarez/go-sqlite v1.21.1 h1:7MZyUPh2XTrHS7xNEHQbrhfMZuPSzhkm2A1qgg0y5NY=
|
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
||||||
github.com/glebarez/go-sqlite v1.21.1/go.mod h1:ISs8MF6yk5cL4n/43rSOmVMGJJjHYr7L2MbZZ5Q4E2E=
|
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||||
github.com/glebarez/sqlite v1.8.0 h1:02X12E2I/4C1n+v90yTqrjRa8yuo7c3KeHI3FRznCvc=
|
github.com/glebarez/sqlite v1.9.0 h1:Aj6bPA12ZEx5GbSF6XADmCkYXlljPNUY+Zf1EQxynXs=
|
||||||
github.com/glebarez/sqlite v1.8.0/go.mod h1:bpET16h1za2KOOMb8+jCp6UBP/iahDpfPQqSaYLTLx8=
|
github.com/glebarez/sqlite v1.9.0/go.mod h1:YBYCoyupOao60lzp1MVBLEjZfgkq0tdB1voAQ09K9zw=
|
||||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
|
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
@ -246,8 +246,8 @@ github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1Y
|
|||||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/xhit/go-simple-mail/v2 v2.15.0 h1:qMXeqcZErUW/Dw6EXxmPuxHzVI8MdxWnEnu2xcisohU=
|
github.com/xhit/go-simple-mail/v2 v2.15.0 h1:qMXeqcZErUW/Dw6EXxmPuxHzVI8MdxWnEnu2xcisohU=
|
||||||
github.com/xhit/go-simple-mail/v2 v2.15.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
|
github.com/xhit/go-simple-mail/v2 v2.15.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
|
||||||
github.com/yeqown/go-qrcode/v2 v2.2.1 h1:Jc1Q916fwC05R8C7mpWDbrT9tyLPaLLKDABoC5XBCe8=
|
github.com/yeqown/go-qrcode/v2 v2.2.2 h1:0comk6jEwi0oWNhKEmzx4JI+Q7XIneAApmFSMKWmSVc=
|
||||||
github.com/yeqown/go-qrcode/v2 v2.2.1/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24=
|
github.com/yeqown/go-qrcode/v2 v2.2.2/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24=
|
||||||
github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0=
|
github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0=
|
||||||
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
|
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
@ -368,14 +368,14 @@ gorm.io/driver/sqlserver v1.5.1/go.mod h1:AYHzzte2msKTmYBYsSIq8ZUsznLJwBdkB2wpI+
|
|||||||
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||||
gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
|
gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
|
||||||
gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||||
modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY=
|
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
|
||||||
modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw=
|
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
|
||||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
|
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
|
||||||
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||||
modernc.org/sqlite v1.21.1 h1:GyDFqNnESLOhwwDRaHGdp2jKLDzpyT/rNLglX3ZkMSU=
|
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
|
||||||
modernc.org/sqlite v1.21.1/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI=
|
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||||
|
@ -5,8 +5,11 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/h44z/wg-portal/internal/app"
|
||||||
"github.com/h44z/wg-portal/internal/config"
|
"github.com/h44z/wg-portal/internal/config"
|
||||||
"github.com/h44z/wg-portal/internal/domain"
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
evbus "github.com/vardius/message-bus"
|
||||||
"github.com/yeqown/go-qrcode/v2"
|
"github.com/yeqown/go-qrcode/v2"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@ -15,6 +18,7 @@ import (
|
|||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
|
bus evbus.MessageBus
|
||||||
tplHandler *TemplateHandler
|
tplHandler *TemplateHandler
|
||||||
|
|
||||||
fsRepo FileSystemRepo // can be nil if storing the configuration is disabled
|
fsRepo FileSystemRepo // can be nil if storing the configuration is disabled
|
||||||
@ -22,7 +26,7 @@ type Manager struct {
|
|||||||
wg WireguardDatabaseRepo
|
wg WireguardDatabaseRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConfigFileManager(cfg *config.Config, users UserDatabaseRepo, wg WireguardDatabaseRepo, fsRepo FileSystemRepo) (*Manager, error) {
|
func NewConfigFileManager(cfg *config.Config, bus evbus.MessageBus, users UserDatabaseRepo, wg WireguardDatabaseRepo, fsRepo FileSystemRepo) (*Manager, error) {
|
||||||
tplHandler, err := newTemplateHandler()
|
tplHandler, err := newTemplateHandler()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to initialize template handler: %w", err)
|
return nil, fmt.Errorf("failed to initialize template handler: %w", err)
|
||||||
@ -30,6 +34,7 @@ func NewConfigFileManager(cfg *config.Config, users UserDatabaseRepo, wg Wiregua
|
|||||||
|
|
||||||
m := &Manager{
|
m := &Manager{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
bus: bus,
|
||||||
tplHandler: tplHandler,
|
tplHandler: tplHandler,
|
||||||
|
|
||||||
fsRepo: fsRepo,
|
fsRepo: fsRepo,
|
||||||
@ -58,6 +63,51 @@ func (m Manager) createStorageDirectory() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m Manager) connectToMessageBus() {
|
||||||
|
if m.fsRepo == nil {
|
||||||
|
return // skip subscription
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = m.bus.Subscribe(app.TopicInterfaceUpdated, m.handleInterfaceUpdatedEvent)
|
||||||
|
_ = m.bus.Subscribe(app.TopicPeerInterfaceUpdated, m.handleInterfaceUpdatedEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Manager) handleInterfaceUpdatedEvent(iface *domain.Interface) {
|
||||||
|
logrus.Errorf("handling interface updated event for %s", iface.Identifier)
|
||||||
|
|
||||||
|
if !iface.SaveConfig || m.fsRepo == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := m.PersistInterfaceConfig(context.Background(), iface.Identifier)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("failed to automatically persist interface config for %s: %v", iface.Identifier, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Manager) handlePeerInterfaceUpdatedEvent(id domain.InterfaceIdentifier) {
|
||||||
|
logrus.Errorf("handling interface updated event for %s", id)
|
||||||
|
|
||||||
|
if m.fsRepo == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
peerInterface, err := m.wg.GetInterface(context.Background(), id)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("failed to load interface %s: %v", id, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !peerInterface.SaveConfig {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = m.PersistInterfaceConfig(context.Background(), peerInterface.Identifier)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("failed to automatically persist interface config for %s: %v", peerInterface.Identifier, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m Manager) GetInterfaceConfig(ctx context.Context, id domain.InterfaceIdentifier) (io.Reader, error) {
|
func (m Manager) GetInterfaceConfig(ctx context.Context, id domain.InterfaceIdentifier) (io.Reader, error) {
|
||||||
iface, peers, err := m.wg.GetInterfaceAndPeers(ctx, id)
|
iface, peers, err := m.wg.GetInterfaceAndPeers(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7,3 +7,5 @@ const TopicUserDeleted = "user:deleted"
|
|||||||
const TopicAuthLogin = "auth:login"
|
const TopicAuthLogin = "auth:login"
|
||||||
const TopicRouteUpdate = "route:update"
|
const TopicRouteUpdate = "route:update"
|
||||||
const TopicRouteRemove = "route:remove"
|
const TopicRouteRemove = "route:remove"
|
||||||
|
const TopicInterfaceUpdated = "interface:updated"
|
||||||
|
const TopicPeerInterfaceUpdated = "peer:interface:updated"
|
||||||
|
@ -414,6 +414,8 @@ func (m Manager) saveInterface(ctx context.Context, iface *domain.Interface, pee
|
|||||||
return nil, fmt.Errorf("post-save hooks failed: %w", err)
|
return nil, fmt.Errorf("post-save hooks failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.bus.Publish(app.TopicInterfaceUpdated, iface)
|
||||||
|
|
||||||
return iface, nil
|
return iface, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +284,10 @@ func (m Manager) savePeers(ctx context.Context, peers ...*domain.Peer) error {
|
|||||||
m.bus.Publish(app.TopicRouteUpdate, "peers updated")
|
m.bus.Publish(app.TopicRouteUpdate, "peers updated")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for iface := range interfaces {
|
||||||
|
m.bus.Publish(app.TopicPeerInterfaceUpdated, iface)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,13 +122,17 @@ func (c Cidr) BroadcastAddr() Cidr {
|
|||||||
a16[off+byteNum] |= 1 << uint(bitInByte)
|
a16[off+byteNum] |= 1 << uint(bitInByte)
|
||||||
}
|
}
|
||||||
if prefix.Addr().Is4() {
|
if prefix.Addr().Is4() {
|
||||||
|
addr := netip.AddrFrom16(a16).Unmap()
|
||||||
return Cidr{
|
return Cidr{
|
||||||
Addr: netip.AddrFrom16(a16).Unmap().String(),
|
Cidr: netip.PrefixFrom(addr, prefix.Bits()).String(),
|
||||||
|
Addr: addr.String(),
|
||||||
NetLength: prefix.Bits(),
|
NetLength: prefix.Bits(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
addr := netip.AddrFrom16(a16) // doesn't unmap
|
||||||
return Cidr{
|
return Cidr{
|
||||||
Addr: netip.AddrFrom16(a16).String(), // doesn't unmap
|
Cidr: netip.PrefixFrom(addr, prefix.Bits()).String(),
|
||||||
|
Addr: addr.String(), // doesn't unmap
|
||||||
NetLength: prefix.Bits(),
|
NetLength: prefix.Bits(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 107 KiB |
Loading…
x
Reference in New Issue
Block a user