diff --git a/.run/swag_build_tool.run.xml b/.run/swag_build_tool.run.xml index 566c7a5..2b8cf7c 100644 --- a/.run/swag_build_tool.run.xml +++ b/.run/swag_build_tool.run.xml @@ -3,7 +3,7 @@ - + diff --git a/internal/ports/api/build_tool/main.go b/cmd/api_build_tool/main.go similarity index 96% rename from internal/ports/api/build_tool/main.go rename to cmd/api_build_tool/main.go index d695e30..4b0caad 100644 --- a/internal/ports/api/build_tool/main.go +++ b/cmd/api_build_tool/main.go @@ -19,7 +19,7 @@ func main() { panic(err) } - apiBasePath := filepath.Join(wd, "/internal/ports/api") + apiBasePath := filepath.Join(wd, "/internal/app/api") apis := []string{"v0"} hasError := false diff --git a/cmd/wg-portal/main.go b/cmd/wg-portal/main.go index 31f9024..11d2be1 100644 --- a/cmd/wg-portal/main.go +++ b/cmd/wg-portal/main.go @@ -2,16 +2,20 @@ package main import ( "context" - "fmt" + "github.com/h44z/wg-portal/internal/app/api/core" + handlersV0 "github.com/h44z/wg-portal/internal/app/api/v0/handlers" + "github.com/h44z/wg-portal/internal/app/auth" + "github.com/h44z/wg-portal/internal/app/users" + "github.com/h44z/wg-portal/internal/app/wireguard" "os" + "strings" "syscall" + "time" "github.com/h44z/wg-portal/internal" "github.com/h44z/wg-portal/internal/adapters" "github.com/h44z/wg-portal/internal/app" "github.com/h44z/wg-portal/internal/config" - "github.com/h44z/wg-portal/internal/ports/api/core" - handlersV0 "github.com/h44z/wg-portal/internal/ports/api/v0/handlers" "github.com/sirupsen/logrus" evbus "github.com/vardius/message-bus" ) @@ -19,10 +23,11 @@ import ( func main() { ctx := internal.SignalAwareContext(context.Background(), syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) - logrus.Infof("Starting web portal...") + logrus.Infof("Starting WireGuard Portal...") cfg, err := config.GetConfig() internal.AssertNoError(err) + setupLogging(cfg) rawDb, err := adapters.NewDatabase(cfg.Database) internal.AssertNoError(err) @@ -32,12 +37,12 @@ func main() { wireGuard := adapters.NewWireGuardRepository() - shouldExit, err := app.HandleProgramArgs(cfg, rawDb, wireGuard) + shouldExit, err := app.HandleProgramArgs(cfg, rawDb) switch { case shouldExit && err == nil: return case shouldExit && err != nil: - logrus.Errorf("failed to process program args: %v", err) + logrus.Errorf("Failed to process program args: %v", err) os.Exit(1) case !shouldExit: internal.AssertNoError(err) @@ -46,9 +51,22 @@ func main() { queueSize := 100 eventBus := evbus.New(queueSize) - backend, err := app.New(cfg, eventBus, database, wireGuard) + userManager, err := users.NewUserManager(cfg, eventBus, database, database) + internal.AssertNoError(err) + + authenticator, err := auth.NewAuthenticator(&cfg.Auth, eventBus, userManager) + internal.AssertNoError(err) + + wireGuardManager, err := wireguard.NewWireGuardManager(cfg, eventBus, wireGuard, database) + internal.AssertNoError(err) + + statisticsCollector, err := wireguard.NewStatisticsCollector(cfg, database, wireGuard) + internal.AssertNoError(err) + + backend, err := app.New(cfg, eventBus, authenticator, userManager, wireGuardManager, statisticsCollector) + internal.AssertNoError(err) + err = backend.Startup(ctx) internal.AssertNoError(err) - backend.Users.StartBackgroundJobs(ctx) apiFrontend := handlersV0.NewRestApi(cfg, backend) @@ -56,10 +74,30 @@ func main() { internal.AssertNoError(err) go webSrv.Run(ctx, cfg.Web.ListeningAddress) - fmt.Println(backend) // TODO: Remove // wait until context gets cancelled <-ctx.Done() - logrus.Infof("Stopped web portal") + logrus.Infof("Stopping WireGuard Portal") + + time.Sleep(5 * time.Second) // wait for (most) goroutines to finish gracefully + + logrus.Infof("Stopped WireGuard Portal") +} + +func setupLogging(cfg *config.Config) { + switch strings.ToLower(cfg.Advanced.LogLevel) { + case "trace": + logrus.SetLevel(logrus.TraceLevel) + case "debug": + logrus.SetLevel(logrus.DebugLevel) + case "info", "information": + logrus.SetLevel(logrus.InfoLevel) + case "warn", "warning": + logrus.SetLevel(logrus.WarnLevel) + case "error": + logrus.SetLevel(logrus.ErrorLevel) + default: + logrus.SetLevel(logrus.WarnLevel) + } } diff --git a/internal/ports/api/core/frontend/.env.development b/frontend/.env.development similarity index 100% rename from internal/ports/api/core/frontend/.env.development rename to frontend/.env.development diff --git a/internal/ports/api/core/frontend/.env.production b/frontend/.env.production similarity index 100% rename from internal/ports/api/core/frontend/.env.production rename to frontend/.env.production diff --git a/internal/ports/api/core/frontend/.gitignore b/frontend/.gitignore similarity index 92% rename from internal/ports/api/core/frontend/.gitignore rename to frontend/.gitignore index 38adffa..6821a23 100644 --- a/internal/ports/api/core/frontend/.gitignore +++ b/frontend/.gitignore @@ -18,7 +18,7 @@ coverage /cypress/screenshots/ # Editor directories and files -.vscode/* +.vscode/extensions.json !.vscode/extensions.json .idea *.suo diff --git a/internal/ports/api/core/frontend/.vscode/extensions.json b/frontend/.vscode/extensions.json similarity index 100% rename from internal/ports/api/core/frontend/.vscode/extensions.json rename to frontend/.vscode/extensions.json diff --git a/internal/ports/api/core/frontend/README.md b/frontend/README.md similarity index 100% rename from internal/ports/api/core/frontend/README.md rename to frontend/README.md diff --git a/internal/ports/api/core/frontend/index.html b/frontend/index.html similarity index 100% rename from internal/ports/api/core/frontend/index.html rename to frontend/index.html diff --git a/internal/ports/api/core/frontend/package-lock.json b/frontend/package-lock.json similarity index 100% rename from internal/ports/api/core/frontend/package-lock.json rename to frontend/package-lock.json diff --git a/internal/ports/api/core/frontend/package.json b/frontend/package.json similarity index 100% rename from internal/ports/api/core/frontend/package.json rename to frontend/package.json diff --git a/internal/ports/api/core/frontend-dist/favicon-large.png b/frontend/public/favicon-large.png similarity index 100% rename from internal/ports/api/core/frontend-dist/favicon-large.png rename to frontend/public/favicon-large.png diff --git a/internal/ports/api/core/frontend-dist/favicon.ico b/frontend/public/favicon.ico similarity index 100% rename from internal/ports/api/core/frontend-dist/favicon.ico rename to frontend/public/favicon.ico diff --git a/internal/ports/api/core/frontend-dist/favicon.png b/frontend/public/favicon.png similarity index 100% rename from internal/ports/api/core/frontend-dist/favicon.png rename to frontend/public/favicon.png diff --git a/internal/ports/api/core/assets/img/header-logo.png b/frontend/public/img/header-logo.png similarity index 100% rename from internal/ports/api/core/assets/img/header-logo.png rename to frontend/public/img/header-logo.png diff --git a/internal/ports/api/core/frontend/src/App.vue b/frontend/src/App.vue similarity index 100% rename from internal/ports/api/core/frontend/src/App.vue rename to frontend/src/App.vue diff --git a/internal/ports/api/core/frontend/src/assets/base.css b/frontend/src/assets/base.css similarity index 100% rename from internal/ports/api/core/frontend/src/assets/base.css rename to frontend/src/assets/base.css diff --git a/internal/ports/api/core/frontend/src/assets/logo.svg b/frontend/src/assets/logo.svg similarity index 100% rename from internal/ports/api/core/frontend/src/assets/logo.svg rename to frontend/src/assets/logo.svg diff --git a/internal/ports/api/core/frontend/src/components/Confirmation.vue b/frontend/src/components/Confirmation.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/Confirmation.vue rename to frontend/src/components/Confirmation.vue diff --git a/internal/ports/api/core/frontend/src/components/InterfaceEditModal.vue b/frontend/src/components/InterfaceEditModal.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/InterfaceEditModal.vue rename to frontend/src/components/InterfaceEditModal.vue diff --git a/internal/ports/api/core/frontend/src/components/Modal.vue b/frontend/src/components/Modal.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/Modal.vue rename to frontend/src/components/Modal.vue diff --git a/internal/ports/api/core/frontend/src/components/PeerEditModal.vue b/frontend/src/components/PeerEditModal.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/PeerEditModal.vue rename to frontend/src/components/PeerEditModal.vue diff --git a/internal/ports/api/core/frontend/src/components/PeerViewModal.vue b/frontend/src/components/PeerViewModal.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/PeerViewModal.vue rename to frontend/src/components/PeerViewModal.vue diff --git a/internal/ports/api/core/frontend/src/components/UserEditModal.vue b/frontend/src/components/UserEditModal.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/UserEditModal.vue rename to frontend/src/components/UserEditModal.vue diff --git a/internal/ports/api/core/frontend/src/components/UserViewModal.vue b/frontend/src/components/UserViewModal.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/UserViewModal.vue rename to frontend/src/components/UserViewModal.vue diff --git a/internal/ports/api/core/frontend/src/components/icons/IconCommunity.vue b/frontend/src/components/icons/IconCommunity.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/icons/IconCommunity.vue rename to frontend/src/components/icons/IconCommunity.vue diff --git a/internal/ports/api/core/frontend/src/components/icons/IconDocumentation.vue b/frontend/src/components/icons/IconDocumentation.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/icons/IconDocumentation.vue rename to frontend/src/components/icons/IconDocumentation.vue diff --git a/internal/ports/api/core/frontend/src/components/icons/IconEcosystem.vue b/frontend/src/components/icons/IconEcosystem.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/icons/IconEcosystem.vue rename to frontend/src/components/icons/IconEcosystem.vue diff --git a/internal/ports/api/core/frontend/src/components/icons/IconSupport.vue b/frontend/src/components/icons/IconSupport.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/icons/IconSupport.vue rename to frontend/src/components/icons/IconSupport.vue diff --git a/internal/ports/api/core/frontend/src/components/icons/IconTooling.vue b/frontend/src/components/icons/IconTooling.vue similarity index 100% rename from internal/ports/api/core/frontend/src/components/icons/IconTooling.vue rename to frontend/src/components/icons/IconTooling.vue diff --git a/internal/ports/api/core/frontend/src/helpers/fetch-wrapper.js b/frontend/src/helpers/fetch-wrapper.js similarity index 100% rename from internal/ports/api/core/frontend/src/helpers/fetch-wrapper.js rename to frontend/src/helpers/fetch-wrapper.js diff --git a/internal/ports/api/core/frontend/src/lang/index.js b/frontend/src/lang/index.js similarity index 80% rename from internal/ports/api/core/frontend/src/lang/index.js rename to frontend/src/lang/index.js index 5bbe593..24c2bc9 100644 --- a/internal/ports/api/core/frontend/src/lang/index.js +++ b/frontend/src/lang/index.js @@ -1,7 +1,7 @@ // src/lang/index.js -import de from './translations/de'; -import en from './translations/en'; -import es from './translations/es'; +import de from './translations/de.json'; +import en from './translations/en.json'; +import es from './translations/es.json'; import {createI18n} from "vue-i18n"; function getStoredLanguage() { diff --git a/internal/ports/api/core/frontend/src/lang/translations/de.json b/frontend/src/lang/translations/de.json similarity index 100% rename from internal/ports/api/core/frontend/src/lang/translations/de.json rename to frontend/src/lang/translations/de.json diff --git a/internal/ports/api/core/frontend/src/lang/translations/en.json b/frontend/src/lang/translations/en.json similarity index 100% rename from internal/ports/api/core/frontend/src/lang/translations/en.json rename to frontend/src/lang/translations/en.json diff --git a/internal/ports/api/core/frontend/src/lang/translations/es.json b/frontend/src/lang/translations/es.json similarity index 100% rename from internal/ports/api/core/frontend/src/lang/translations/es.json rename to frontend/src/lang/translations/es.json diff --git a/internal/ports/api/core/frontend/src/main.js b/frontend/src/main.js similarity index 100% rename from internal/ports/api/core/frontend/src/main.js rename to frontend/src/main.js diff --git a/internal/ports/api/core/frontend/src/router/index.js b/frontend/src/router/index.js similarity index 100% rename from internal/ports/api/core/frontend/src/router/index.js rename to frontend/src/router/index.js diff --git a/internal/ports/api/core/frontend/src/stores/auth.js b/frontend/src/stores/auth.js similarity index 99% rename from internal/ports/api/core/frontend/src/stores/auth.js rename to frontend/src/stores/auth.js index b2c1bb7..594c3e5 100644 --- a/internal/ports/api/core/frontend/src/stores/auth.js +++ b/frontend/src/stores/auth.js @@ -2,7 +2,7 @@ import { defineStore } from 'pinia' import { notify } from "@kyvg/vue3-notification"; import { apiWrapper } from '../helpers/fetch-wrapper.js' -import router from '../router/index.js' +import router from '../router' export const authStore = defineStore({ id: 'auth', diff --git a/internal/ports/api/core/frontend/src/stores/interfaces.js b/frontend/src/stores/interfaces.js similarity index 100% rename from internal/ports/api/core/frontend/src/stores/interfaces.js rename to frontend/src/stores/interfaces.js diff --git a/internal/ports/api/core/frontend/src/stores/peers.js b/frontend/src/stores/peers.js similarity index 100% rename from internal/ports/api/core/frontend/src/stores/peers.js rename to frontend/src/stores/peers.js diff --git a/internal/ports/api/core/frontend/src/stores/security.js b/frontend/src/stores/security.js similarity index 100% rename from internal/ports/api/core/frontend/src/stores/security.js rename to frontend/src/stores/security.js diff --git a/internal/ports/api/core/frontend/src/stores/users.js b/frontend/src/stores/users.js similarity index 100% rename from internal/ports/api/core/frontend/src/stores/users.js rename to frontend/src/stores/users.js diff --git a/internal/ports/api/core/frontend/src/views/AboutView.vue b/frontend/src/views/AboutView.vue similarity index 100% rename from internal/ports/api/core/frontend/src/views/AboutView.vue rename to frontend/src/views/AboutView.vue diff --git a/internal/ports/api/core/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue similarity index 100% rename from internal/ports/api/core/frontend/src/views/HomeView.vue rename to frontend/src/views/HomeView.vue diff --git a/internal/ports/api/core/frontend/src/views/InterfaceView.vue b/frontend/src/views/InterfaceView.vue similarity index 100% rename from internal/ports/api/core/frontend/src/views/InterfaceView.vue rename to frontend/src/views/InterfaceView.vue diff --git a/internal/ports/api/core/frontend/src/views/LoginView.vue b/frontend/src/views/LoginView.vue similarity index 100% rename from internal/ports/api/core/frontend/src/views/LoginView.vue rename to frontend/src/views/LoginView.vue diff --git a/internal/ports/api/core/frontend/src/views/UserView.vue b/frontend/src/views/UserView.vue similarity index 100% rename from internal/ports/api/core/frontend/src/views/UserView.vue rename to frontend/src/views/UserView.vue diff --git a/internal/ports/api/core/frontend/vite.config.js b/frontend/vite.config.js similarity index 92% rename from internal/ports/api/core/frontend/vite.config.js rename to frontend/vite.config.js index 32a0132..1a0bc42 100644 --- a/internal/ports/api/core/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -12,7 +12,7 @@ export default defineConfig({ } }, build: { - outDir: '../frontend-dist', + outDir: '../internal/app/api/core/frontend-dist', emptyOutDir: true }, // local dev api (proxy to avoid cors problems) diff --git a/go.mod b/go.mod index 3cf6186..c00b77a 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/go-ldap/ldap/v3 v3.4.4 github.com/h44z/lightmigrate v1.0.0 github.com/h44z/lightmigrate-mysql v0.0.0-20220114152421-d1fec9d056f1 + github.com/prometheus-community/pro-bing v0.2.0 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.1 github.com/swaggo/swag v1.8.9 @@ -53,6 +54,7 @@ require ( github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.9 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/sessions v1.2.1 // indirect @@ -82,11 +84,11 @@ require ( github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect github.com/ugorji/go/codec v1.2.8 // indirect github.com/vishvananda/netns v0.0.2 // indirect - golang.org/x/net v0.5.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.4.0 // indirect - golang.org/x/text v0.6.0 // indirect - golang.org/x/tools v0.5.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/tools v0.6.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index 76f79f8..e2b69ca 100644 --- a/go.sum +++ b/go.sum @@ -98,6 +98,7 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -191,6 +192,8 @@ 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/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= +github.com/prometheus-community/pro-bing v0.2.0 h1:hyK7yPFndU3LCDwEQJwPQUCjNkp1DGP/VxyzrWfXZUU= +github.com/prometheus-community/pro-bing v0.2.0/go.mod h1:20arNb2S8rNG3EtmjHyZZU92cfbhQx7oCHZ9sulAV+I= github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg= github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b h1:aUNXCGgukb4gtY99imuIeoh8Vr0GSwAlYxPAhqZrpFc= github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg= @@ -253,7 +256,7 @@ golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80 golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -266,8 +269,8 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= @@ -275,8 +278,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ 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.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -297,8 +300,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= @@ -309,13 +312,13 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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= -golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= -golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c h1:Okh6a1xpnJslG9Mn84pId1Mn+Q8cvpo4HCeeFWHo0cA= diff --git a/internal/adapters/database.go b/internal/adapters/database.go index c2eb02a..ad44a5d 100644 --- a/internal/adapters/database.go +++ b/internal/adapters/database.go @@ -6,6 +6,8 @@ import ( "errors" "fmt" "github.com/sirupsen/logrus" + "gorm.io/gorm/logger" + "gorm.io/gorm/utils" "os" "path/filepath" "strings" @@ -26,13 +28,74 @@ import ( var sqlMigrationFs embed.FS var SchemaVersion uint64 = 1 +// GormLogger is a custom logger for Gorm, making it use logrus. +type GormLogger struct { + SlowThreshold time.Duration + SourceField string + IgnoreErrRecordNotFound bool + Debug bool +} + +func NewLogger(slowThreshold time.Duration, debug bool) *GormLogger { + return &GormLogger{ + SlowThreshold: slowThreshold, + Debug: debug, + IgnoreErrRecordNotFound: true, + SourceField: "src", + } +} + +func (l *GormLogger) LogMode(logger.LogLevel) logger.Interface { + return l +} + +func (l *GormLogger) Info(ctx context.Context, s string, args ...interface{}) { + logrus.WithContext(ctx).Infof(s, args) +} + +func (l *GormLogger) Warn(ctx context.Context, s string, args ...interface{}) { + logrus.WithContext(ctx).Warnf(s, args) +} + +func (l *GormLogger) Error(ctx context.Context, s string, args ...interface{}) { + logrus.WithContext(ctx).Errorf(s, args) +} + +func (l *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { + elapsed := time.Since(begin) + sql, rows := fc() + fields := logrus.Fields{ + "rows": rows, + "duration": elapsed, + } + if l.SourceField != "" { + fields[l.SourceField] = utils.FileWithLineNum() + } + if err != nil && !(errors.Is(err, gorm.ErrRecordNotFound) && l.IgnoreErrRecordNotFound) { + fields[logrus.ErrorKey] = err + logrus.WithContext(ctx).WithFields(fields).Errorf("%s", sql) + return + } + + if l.SlowThreshold != 0 && elapsed > l.SlowThreshold { + logrus.WithContext(ctx).WithFields(fields).Warnf("%s", sql) + return + } + + if l.Debug { + logrus.WithContext(ctx).WithFields(fields).Debugf("%s", sql) + } +} + func NewDatabase(cfg config.DatabaseConfig) (*gorm.DB, error) { var gormDb *gorm.DB var err error switch cfg.Type { case config.DatabaseMySQL: - gormDb, err = gorm.Open(gormMySQL.Open(cfg.DSN), &gorm.Config{}) + gormDb, err = gorm.Open(gormMySQL.Open(cfg.DSN), &gorm.Config{ + Logger: NewLogger(cfg.SlowQueryThreshold, cfg.Debug), + }) if err != nil { return nil, fmt.Errorf("failed to open MySQL database: %w", err) } @@ -46,12 +109,16 @@ func NewDatabase(cfg config.DatabaseConfig) (*gorm.DB, error) { return nil, fmt.Errorf("failed to ping MySQL database: %w", err) } case config.DatabaseMsSQL: - gormDb, err = gorm.Open(sqlserver.Open(cfg.DSN), &gorm.Config{}) + gormDb, err = gorm.Open(sqlserver.Open(cfg.DSN), &gorm.Config{ + Logger: NewLogger(cfg.SlowQueryThreshold, cfg.Debug), + }) if err != nil { return nil, fmt.Errorf("failed to open sqlserver database: %w", err) } case config.DatabasePostgres: - gormDb, err = gorm.Open(postgres.Open(cfg.DSN), &gorm.Config{}) + gormDb, err = gorm.Open(postgres.Open(cfg.DSN), &gorm.Config{ + Logger: NewLogger(cfg.SlowQueryThreshold, cfg.Debug), + }) if err != nil { return nil, fmt.Errorf("failed to open Postgres database: %w", err) } @@ -61,7 +128,10 @@ func NewDatabase(cfg config.DatabaseConfig) (*gorm.DB, error) { return nil, fmt.Errorf("failed to create database base directory: %w", err) } } - gormDb, err = gorm.Open(sqlite.Open(cfg.DSN), &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}) + gormDb, err = gorm.Open(sqlite.Open(cfg.DSN), &gorm.Config{ + Logger: NewLogger(cfg.SlowQueryThreshold, cfg.Debug), + DisableForeignKeyConstraintWhenMigrating: true, + }) if err != nil { return nil, fmt.Errorf("failed to open sqlite database: %w", err) } @@ -89,9 +159,11 @@ func NewSqlRepository(db *gorm.DB) (*SqlRepo, error) { func (r *SqlRepo) migrate() error { // TODO: REMOVE - logrus.Warnf("user migration: %v", r.db.AutoMigrate(&domain.User{})) - logrus.Warnf("interface migration: %v", r.db.AutoMigrate(&domain.Interface{})) - logrus.Warnf("peer migration: %v", r.db.AutoMigrate(&domain.Peer{})) + logrus.Debugf("user migration: %v", r.db.AutoMigrate(&domain.User{})) + logrus.Debugf("interface migration: %v", r.db.AutoMigrate(&domain.Interface{})) + logrus.Debugf("peer migration: %v", r.db.AutoMigrate(&domain.Peer{})) + logrus.Debugf("peer status migration: %v", r.db.AutoMigrate(&domain.PeerStatus{})) + logrus.Debugf("interface status migration: %v", r.db.AutoMigrate(&domain.InterfaceStatus{})) // TODO: REMOVE THE ABOVE LINES rawDb, err := r.db.DB() @@ -267,7 +339,7 @@ func (r *SqlRepo) GetInterfaceIps(ctx context.Context) (map[domain.InterfaceIden err := r.db.WithContext(ctx). Table("interface_addresses"). - Joins("LEFT JOIN cidrs ON interface_addresses.cidr_addr = cidrs.addr AND interface_addresses.cidr_net_length = cidrs.net_len"). + Joins("LEFT JOIN cidrs ON interface_addresses.cidr_cidr = cidrs.cidr"). Scan(&ips).Error if err != nil { return nil, err @@ -525,3 +597,113 @@ func (r *SqlRepo) upsertUser(tx *gorm.DB, user *domain.User) error { } // endregion users + +// region statistics + +func (r *SqlRepo) UpdateInterfaceStatus(ctx context.Context, id domain.InterfaceIdentifier, updateFunc func(in *domain.InterfaceStatus) (*domain.InterfaceStatus, error)) error { + err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + in, err := r.getOrCreateInterfaceStatus(tx, id) + if err != nil { + return err // return any error will roll back + } + + in, err = updateFunc(in) + if err != nil { + return err + } + + err = r.upsertInterfaceStatus(tx, in) + if err != nil { + return err + } + + // return nil will commit the whole transaction + return nil + }) + if err != nil { + return err + } + + return nil +} + +func (r *SqlRepo) getOrCreateInterfaceStatus(tx *gorm.DB, id domain.InterfaceIdentifier) (*domain.InterfaceStatus, error) { + var in domain.InterfaceStatus + + // defaults will be applied to newly created record + defaults := domain.InterfaceStatus{ + InterfaceId: id, + UpdatedAt: time.Now(), + } + + err := tx.Attrs(defaults).FirstOrCreate(&in, id).Error + if err != nil { + return nil, err + } + + return &in, nil +} + +func (r *SqlRepo) upsertInterfaceStatus(tx *gorm.DB, in *domain.InterfaceStatus) error { + err := tx.Save(in).Error + if err != nil { + return err + } + + return nil +} + +func (r *SqlRepo) UpdatePeerStatus(ctx context.Context, id domain.PeerIdentifier, updateFunc func(in *domain.PeerStatus) (*domain.PeerStatus, error)) error { + err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + in, err := r.getOrCreatePeerStatus(tx, id) + if err != nil { + return err // return any error will roll back + } + + in, err = updateFunc(in) + if err != nil { + return err + } + + err = r.upsertPeerStatus(tx, in) + if err != nil { + return err + } + + // return nil will commit the whole transaction + return nil + }) + if err != nil { + return err + } + + return nil +} + +func (r *SqlRepo) getOrCreatePeerStatus(tx *gorm.DB, id domain.PeerIdentifier) (*domain.PeerStatus, error) { + var in domain.PeerStatus + + // defaults will be applied to newly created record + defaults := domain.PeerStatus{ + PeerId: id, + UpdatedAt: time.Now(), + } + + err := tx.Attrs(defaults).FirstOrCreate(&in, id).Error + if err != nil { + return nil, err + } + + return &in, nil +} + +func (r *SqlRepo) upsertPeerStatus(tx *gorm.DB, in *domain.PeerStatus) error { + err := tx.Save(in).Error + if err != nil { + return err + } + + return nil +} + +// endregion statistics diff --git a/internal/ports/api/core/assets.go b/internal/app/api/core/assets.go similarity index 100% rename from internal/ports/api/core/assets.go rename to internal/app/api/core/assets.go diff --git a/internal/ports/api/core/assets/css/bootstrap.min.css b/internal/app/api/core/assets/css/bootstrap.min.css similarity index 100% rename from internal/ports/api/core/assets/css/bootstrap.min.css rename to internal/app/api/core/assets/css/bootstrap.min.css diff --git a/internal/ports/api/core/assets/doc/v0_swagger.json b/internal/app/api/core/assets/doc/v0_swagger.json similarity index 74% rename from internal/ports/api/core/assets/doc/v0_swagger.json rename to internal/app/api/core/assets/doc/v0_swagger.json index f0572e4..bb62a25 100644 --- a/internal/ports/api/core/assets/doc/v0_swagger.json +++ b/internal/app/api/core/assets/doc/v0_swagger.json @@ -283,6 +283,49 @@ } } }, + "/interface/new": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "Interface" + ], + "summary": "Create the new interface record.", + "operationId": "interfaces_handleCreatePost", + "parameters": [ + { + "description": "The interface data", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.Interface" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Interface" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Error" + } + } + } + } + }, "/interface/peers/{id}": { "get": { "produces": [ @@ -312,6 +355,82 @@ } } }, + "/interface/prepare": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Interface" + ], + "summary": "Prepare a new interface.", + "operationId": "interfaces_handlePrepareGet", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Interface" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Error" + } + } + } + } + }, + "/interface/{id}": { + "put": { + "produces": [ + "application/json" + ], + "tags": [ + "Interface" + ], + "summary": "Update the interface record.", + "operationId": "interfaces_handleUpdatePut", + "parameters": [ + { + "type": "string", + "description": "The interface identifier", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "The interface data", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.Interface" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Interface" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Error" + } + } + } + } + }, "/now": { "get": { "description": "Nothing more to describe...", @@ -396,6 +515,128 @@ } } } + }, + "/users/new": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "Users" + ], + "summary": "Create the new user record.", + "operationId": "users_handleCreatePost", + "parameters": [ + { + "description": "The user data", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.User" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.User" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Error" + } + } + } + } + }, + "/users/{id}": { + "put": { + "produces": [ + "application/json" + ], + "tags": [ + "Users" + ], + "summary": "Update the user record.", + "operationId": "users_handleUpdatePut", + "parameters": [ + { + "type": "string", + "description": "The user identifier", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "The user data", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.User" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.User" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Error" + } + } + } + } + }, + "/users/{id}/peers": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Users" + ], + "summary": "Get peers for the given user.", + "operationId": "users_handlePeersGet", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/model.Peer" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Error" + } + } + } + } } }, "definitions": { @@ -434,11 +675,17 @@ }, "Dns": { "description": "the dns server that should be set if the interface is up, comma separated", - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "DnsSearch": { "description": "the dns search option string that should be set if the interface is up, will be appended to DnsStr", - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "EnabledPeers": { "type": "integer" @@ -467,15 +714,24 @@ }, "PeerDefAllowedIPs": { "description": "the default allowed IP string for the peer", - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "PeerDefDns": { "description": "the default dns server for the peer", - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "PeerDefDnsSearch": { "description": "the default dns search options for the peer", - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "PeerDefEndpoint": { "description": "the default endpoint for the peer", @@ -491,7 +747,10 @@ }, "PeerDefNetwork": { "description": "the default subnets from which peers will get their IP addresses, comma seperated", - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "PeerDefPersistentKeepalive": { "description": "the default persistent keep-alive Value", diff --git a/internal/ports/api/core/assets/doc/v0_swagger.yaml b/internal/app/api/core/assets/doc/v0_swagger.yaml similarity index 76% rename from internal/ports/api/core/assets/doc/v0_swagger.yaml rename to internal/app/api/core/assets/doc/v0_swagger.yaml index 287279b..cd87dcb 100644 --- a/internal/ports/api/core/assets/doc/v0_swagger.yaml +++ b/internal/app/api/core/assets/doc/v0_swagger.yaml @@ -26,11 +26,15 @@ definitions: Dns: description: the dns server that should be set if the interface is up, comma separated - type: string + items: + type: string + type: array DnsSearch: description: the dns search option string that should be set if the interface is up, will be appended to DnsStr - type: string + items: + type: string + type: array EnabledPeers: type: integer FirewallMark: @@ -52,13 +56,19 @@ definitions: type: integer PeerDefAllowedIPs: description: the default allowed IP string for the peer - type: string + items: + type: string + type: array PeerDefDns: description: the default dns server for the peer - type: string + items: + type: string + type: array PeerDefDnsSearch: description: the default dns search options for the peer - type: string + items: + type: string + type: array PeerDefEndpoint: description: the default endpoint for the peer type: string @@ -71,7 +81,9 @@ definitions: PeerDefNetwork: description: the default subnets from which peers will get their IP addresses, comma seperated - type: string + items: + type: string + type: array PeerDefPersistentKeepalive: description: the default persistent keep-alive Value type: integer @@ -413,6 +425,39 @@ paths: summary: Get the current host name. tags: - Testing + /interface/{id}: + put: + operationId: interfaces_handleUpdatePut + parameters: + - description: The interface identifier + in: path + name: id + required: true + type: string + - description: The interface data + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.Interface' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.Interface' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Error' + summary: Update the interface record. + tags: + - Interface /interface/all: get: operationId: interfaces_handleAllGet @@ -453,6 +498,34 @@ paths: summary: Get single interface. tags: - Interface + /interface/new: + post: + operationId: interfaces_handleCreatePost + parameters: + - description: The interface data + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.Interface' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.Interface' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Error' + summary: Create the new interface record. + tags: + - Interface /interface/peers/{id}: get: operationId: interfaces_handlePeersGet @@ -472,6 +545,23 @@ paths: summary: Get peers for the given interface. tags: - Interface + /interface/prepare: + get: + operationId: interfaces_handlePrepareGet + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.Interface' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Error' + summary: Prepare a new interface. + tags: + - Interface /now: get: description: Nothing more to describe... @@ -528,4 +618,84 @@ paths: summary: Get all user records. tags: - Users + /users/{id}: + put: + operationId: users_handleUpdatePut + parameters: + - description: The user identifier + in: path + name: id + required: true + type: string + - description: The user data + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.User' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.User' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Error' + summary: Update the user record. + tags: + - Users + /users/{id}/peers: + get: + operationId: users_handlePeersGet + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/model.Peer' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Error' + summary: Get peers for the given user. + tags: + - Users + /users/new: + post: + operationId: users_handleCreatePost + parameters: + - description: The user data + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.User' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.User' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Error' + summary: Create the new user record. + tags: + - Users swagger: "2.0" diff --git a/internal/ports/api/core/assets/fonts/FontAwesome.otf b/internal/app/api/core/assets/fonts/FontAwesome.otf similarity index 100% rename from internal/ports/api/core/assets/fonts/FontAwesome.otf rename to internal/app/api/core/assets/fonts/FontAwesome.otf diff --git a/internal/ports/api/core/assets/fonts/fa-brands-400.eot b/internal/app/api/core/assets/fonts/fa-brands-400.eot similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-brands-400.eot rename to internal/app/api/core/assets/fonts/fa-brands-400.eot diff --git a/internal/ports/api/core/assets/fonts/fa-brands-400.svg b/internal/app/api/core/assets/fonts/fa-brands-400.svg similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-brands-400.svg rename to internal/app/api/core/assets/fonts/fa-brands-400.svg diff --git a/internal/ports/api/core/assets/fonts/fa-brands-400.ttf b/internal/app/api/core/assets/fonts/fa-brands-400.ttf similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-brands-400.ttf rename to internal/app/api/core/assets/fonts/fa-brands-400.ttf diff --git a/internal/ports/api/core/assets/fonts/fa-brands-400.woff b/internal/app/api/core/assets/fonts/fa-brands-400.woff similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-brands-400.woff rename to internal/app/api/core/assets/fonts/fa-brands-400.woff diff --git a/internal/ports/api/core/assets/fonts/fa-brands-400.woff2 b/internal/app/api/core/assets/fonts/fa-brands-400.woff2 similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-brands-400.woff2 rename to internal/app/api/core/assets/fonts/fa-brands-400.woff2 diff --git a/internal/ports/api/core/assets/fonts/fa-regular-400.eot b/internal/app/api/core/assets/fonts/fa-regular-400.eot similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-regular-400.eot rename to internal/app/api/core/assets/fonts/fa-regular-400.eot diff --git a/internal/ports/api/core/assets/fonts/fa-regular-400.svg b/internal/app/api/core/assets/fonts/fa-regular-400.svg similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-regular-400.svg rename to internal/app/api/core/assets/fonts/fa-regular-400.svg diff --git a/internal/ports/api/core/assets/fonts/fa-regular-400.ttf b/internal/app/api/core/assets/fonts/fa-regular-400.ttf similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-regular-400.ttf rename to internal/app/api/core/assets/fonts/fa-regular-400.ttf diff --git a/internal/ports/api/core/assets/fonts/fa-regular-400.woff b/internal/app/api/core/assets/fonts/fa-regular-400.woff similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-regular-400.woff rename to internal/app/api/core/assets/fonts/fa-regular-400.woff diff --git a/internal/ports/api/core/assets/fonts/fa-regular-400.woff2 b/internal/app/api/core/assets/fonts/fa-regular-400.woff2 similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-regular-400.woff2 rename to internal/app/api/core/assets/fonts/fa-regular-400.woff2 diff --git a/internal/ports/api/core/assets/fonts/fa-solid-900.eot b/internal/app/api/core/assets/fonts/fa-solid-900.eot similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-solid-900.eot rename to internal/app/api/core/assets/fonts/fa-solid-900.eot diff --git a/internal/ports/api/core/assets/fonts/fa-solid-900.svg b/internal/app/api/core/assets/fonts/fa-solid-900.svg similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-solid-900.svg rename to internal/app/api/core/assets/fonts/fa-solid-900.svg diff --git a/internal/ports/api/core/assets/fonts/fa-solid-900.ttf b/internal/app/api/core/assets/fonts/fa-solid-900.ttf similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-solid-900.ttf rename to internal/app/api/core/assets/fonts/fa-solid-900.ttf diff --git a/internal/ports/api/core/assets/fonts/fa-solid-900.woff b/internal/app/api/core/assets/fonts/fa-solid-900.woff similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-solid-900.woff rename to internal/app/api/core/assets/fonts/fa-solid-900.woff diff --git a/internal/ports/api/core/assets/fonts/fa-solid-900.woff2 b/internal/app/api/core/assets/fonts/fa-solid-900.woff2 similarity index 100% rename from internal/ports/api/core/assets/fonts/fa-solid-900.woff2 rename to internal/app/api/core/assets/fonts/fa-solid-900.woff2 diff --git a/internal/ports/api/core/assets/fonts/font-awesome.min.css b/internal/app/api/core/assets/fonts/font-awesome.min.css similarity index 100% rename from internal/ports/api/core/assets/fonts/font-awesome.min.css rename to internal/app/api/core/assets/fonts/font-awesome.min.css diff --git a/internal/ports/api/core/assets/fonts/fontawesome-all.min.css b/internal/app/api/core/assets/fonts/fontawesome-all.min.css similarity index 100% rename from internal/ports/api/core/assets/fonts/fontawesome-all.min.css rename to internal/app/api/core/assets/fonts/fontawesome-all.min.css diff --git a/internal/ports/api/core/assets/fonts/fontawesome-webfont.eot b/internal/app/api/core/assets/fonts/fontawesome-webfont.eot similarity index 100% rename from internal/ports/api/core/assets/fonts/fontawesome-webfont.eot rename to internal/app/api/core/assets/fonts/fontawesome-webfont.eot diff --git a/internal/ports/api/core/assets/fonts/fontawesome-webfont.svg b/internal/app/api/core/assets/fonts/fontawesome-webfont.svg similarity index 100% rename from internal/ports/api/core/assets/fonts/fontawesome-webfont.svg rename to internal/app/api/core/assets/fonts/fontawesome-webfont.svg diff --git a/internal/ports/api/core/assets/fonts/fontawesome-webfont.ttf b/internal/app/api/core/assets/fonts/fontawesome-webfont.ttf similarity index 100% rename from internal/ports/api/core/assets/fonts/fontawesome-webfont.ttf rename to internal/app/api/core/assets/fonts/fontawesome-webfont.ttf diff --git a/internal/ports/api/core/assets/fonts/fontawesome-webfont.woff b/internal/app/api/core/assets/fonts/fontawesome-webfont.woff similarity index 100% rename from internal/ports/api/core/assets/fonts/fontawesome-webfont.woff rename to internal/app/api/core/assets/fonts/fontawesome-webfont.woff diff --git a/internal/ports/api/core/assets/fonts/fontawesome-webfont.woff2 b/internal/app/api/core/assets/fonts/fontawesome-webfont.woff2 similarity index 100% rename from internal/ports/api/core/assets/fonts/fontawesome-webfont.woff2 rename to internal/app/api/core/assets/fonts/fontawesome-webfont.woff2 diff --git a/internal/ports/api/core/assets/fonts/fontawesome5-overrides.min.css b/internal/app/api/core/assets/fonts/fontawesome5-overrides.min.css similarity index 100% rename from internal/ports/api/core/assets/fonts/fontawesome5-overrides.min.css rename to internal/app/api/core/assets/fonts/fontawesome5-overrides.min.css diff --git a/internal/ports/api/core/assets/img/header-logo-small.png b/internal/app/api/core/assets/img/header-logo-small.png similarity index 100% rename from internal/ports/api/core/assets/img/header-logo-small.png rename to internal/app/api/core/assets/img/header-logo-small.png diff --git a/internal/ports/api/core/frontend-dist/img/header-logo.png b/internal/app/api/core/assets/img/header-logo.png similarity index 100% rename from internal/ports/api/core/frontend-dist/img/header-logo.png rename to internal/app/api/core/assets/img/header-logo.png diff --git a/internal/ports/api/core/assets/js/bootstrap.bundle.min.js b/internal/app/api/core/assets/js/bootstrap.bundle.min.js similarity index 100% rename from internal/ports/api/core/assets/js/bootstrap.bundle.min.js rename to internal/app/api/core/assets/js/bootstrap.bundle.min.js diff --git a/internal/ports/api/core/assets/js/jquery.easing.js b/internal/app/api/core/assets/js/jquery.easing.js similarity index 100% rename from internal/ports/api/core/assets/js/jquery.easing.js rename to internal/app/api/core/assets/js/jquery.easing.js diff --git a/internal/ports/api/core/assets/js/jquery.min.js b/internal/app/api/core/assets/js/jquery.min.js similarity index 100% rename from internal/ports/api/core/assets/js/jquery.min.js rename to internal/app/api/core/assets/js/jquery.min.js diff --git a/internal/ports/api/core/assets/js/popper.min.js b/internal/app/api/core/assets/js/popper.min.js similarity index 100% rename from internal/ports/api/core/assets/js/popper.min.js rename to internal/app/api/core/assets/js/popper.min.js diff --git a/internal/ports/api/core/assets/js/rapidoc-min.js b/internal/app/api/core/assets/js/rapidoc-min.js similarity index 100% rename from internal/ports/api/core/assets/js/rapidoc-min.js rename to internal/app/api/core/assets/js/rapidoc-min.js diff --git a/internal/ports/api/core/assets/tpl/index.gohtml b/internal/app/api/core/assets/tpl/index.gohtml similarity index 100% rename from internal/ports/api/core/assets/tpl/index.gohtml rename to internal/app/api/core/assets/tpl/index.gohtml diff --git a/internal/ports/api/core/assets/tpl/prt_footer.gohtml b/internal/app/api/core/assets/tpl/prt_footer.gohtml similarity index 100% rename from internal/ports/api/core/assets/tpl/prt_footer.gohtml rename to internal/app/api/core/assets/tpl/prt_footer.gohtml diff --git a/internal/ports/api/core/assets/tpl/prt_nav.gohtml b/internal/app/api/core/assets/tpl/prt_nav.gohtml similarity index 100% rename from internal/ports/api/core/assets/tpl/prt_nav.gohtml rename to internal/app/api/core/assets/tpl/prt_nav.gohtml diff --git a/internal/ports/api/core/assets/tpl/rapidoc.gohtml b/internal/app/api/core/assets/tpl/rapidoc.gohtml similarity index 100% rename from internal/ports/api/core/assets/tpl/rapidoc.gohtml rename to internal/app/api/core/assets/tpl/rapidoc.gohtml diff --git a/internal/app/api/core/frontend-dist/assets/UserView-f9bf06a4.js b/internal/app/api/core/frontend-dist/assets/UserView-f9bf06a4.js new file mode 100644 index 0000000..4365516 --- /dev/null +++ b/internal/app/api/core/frontend-dist/assets/UserView-f9bf06a4.js @@ -0,0 +1 @@ +import{d as T,a as P,A as w,u as A,c as U,r as E,w as O,o as u,b as B,e as x,f as n,_ as M,g as e,h,t as o,i as m,v as g,j as $,k as V,l as k,m as z,F as I,n as D,p as W,q as L,s as F,x as H}from "./index-62a1c0a6.js";const C="/user",N=T({id:"users",state:()=>({userPeers:[],users:[],filter:"",pageSize:10,pageOffset:0,pages:[],fetching:!1}),getters:{Find: t=> l=>t.users.find(i=>i.Identifier===l),Count: t=>t.users.length,FilteredCount: t=>t.Filtered.length,All: t=>t.users,Peers: t=>t.userPeers,Filtered: t=>t.filter?t.users.filter(l=>l.Firstname.includes(t.filter)||l.Lastname.includes(t.filter)||l.Email.includes(t.filter)||l.Identifier.includes(t.filter)):t.users,FilteredAndPaged: t=>t.Filtered.slice(t.pageOffset,t.pageOffset+t.pageSize),isFetching: t=>t.fetching,hasNextPage: t=>t.pageOffsett.pageOffset>0,currentPage: t=>t.pageOffset/t.pageSize+1},actions:{afterPageSizeChange(){this.pageOffset=0,this.calculatePages()},calculatePages(){let t=1;this.pages=[];for(let l=0; l{this.setUsers([]),console.log("Failed to load users: ",t),w({title:"Backend Connection Failure",text:"Failed to load users!"})})},async DeleteUser(t){return this.fetching=!0,P.delete(`${C}/`+t).then(()=>{this.users=this.users.filter(l=>l.Identifier!==t),this.fetching=!1}).catch(l=>{throw this.fetching=!1,console.log(l),new Error(l)})},async UpdateUser(t, l){return this.fetching=!0,P.put(`${C}/`+t,l).then(i=>{let v=this.users.findIndex(_=>_.Identifier===t);this.users[v]=i,this.fetching=!1}).catch(i=>{throw this.fetching=!1,console.log(i),new Error(i)})},async CreateUser(t){return this.fetching=!0,P.post(`${C}/new`,t).then(l=>{this.users.push(l),this.fetching=!1}).catch(l=>{throw this.fetching=!1,console.log(l),new Error(l)})},async LoadUserPeers(t){return this.fetching=!0,P.get(`${C}/${t}/peers`).then(this.setUserPeers).catch(l=>{this.setUserPeers([]),console.log("Failed to load user peers for ",t,": ",l),w({title:"Backend Connection Failure",text:"Failed to load user peers!"})})}}}),j=e("legend",{class:"mt-4"},"General",-1),q={key:0,class:"form-group"},G={class:"form-label mt-4"},K={class:"form-group"},Y={class:"form-label mt-4"},J={key:1,class:"form-group"},Q={class:"form-label mt-4"},R={key:0,id:"passwordHelp",class:"form-text text-muted"},X=e("legend",{class:"mt-4"},"User Information",-1),Z={class:"form-group"},ee={class:"form-label mt-4"},se={class:"row"},te={class:"form-group col-md-6"},le={class:"form-label mt-4"},oe={class:"form-group col-md-6"},ae={class:"form-label mt-4"},ne={class:"row"},ie={class:"form-group col-md-6"},re={class:"form-label mt-4"},de={class:"form-group col-md-6"},ce={class:"form-label mt-4"},ue=e("legend",{class:"mt-4"},"Notes",-1),he={class:"form-group"},pe={class:"form-label mt-4"},fe=e("legend",{class:"mt-4"},"State",-1),me={class:"form-check form-switch"},_e=e("label",{class:"form-check-label"},"Disabled",-1),ve={class:"form-check form-switch"},ge=e("label",{class:"form-check-label"},"Is Admin",-1),be={class:"flex-fill text-start"},$e=["onClick"],ke=["onClick"],ye=["onClick"],Pe={__name:"UserEditModal",props:{userId:String,visible:Boolean},emits:["close"],setup(t, {emit:l}){const i=t,{t:v}=A(),_=N(),a=U(()=>_.Find(i.userId)),d=U(()=>i.visible?a.value?v("users.edit")+": "+a.value.Identifier:v("users.new"):""),s=E(b());function b(){return{Identifier:"",Email:"",Source:"db",IsAdmin:!1,Firstname:"",Lastname:"",Phone:"",Department:"",Notes:"",Password:"",Disabled:!1}}O(()=>i.visible,async(f, r)=>{r===!1&&f===!0&&(a.value?(s.value.Identifier=a.value.Identifier,s.value.Email=a.value.Email,s.value.Source=a.value.Source,s.value.IsAdmin=a.value.IsAdmin,s.value.Firstname=a.value.Firstname,s.value.Lastname=a.value.Lastname,s.value.Phone=a.value.Phone,s.value.Department=a.value.Department,s.value.Notes=a.value.Notes,s.value.Password="",s.value.Disabled=a.value.Disabled):s.value=b())});function p(){s.value=b(),l("close")}async function S(){try{i.userId!=="#NEW#"?await _.UpdateUser(a.value.Identifier,s.value):await _.CreateUser(s.value),p()}catch{w({title:"Backend Connection Failure",text:"Failed to save user!",type:"error"})}}async function y(){try{await _.DeleteUser(a.value.Identifier),p()}catch{w({title:"Backend Connection Failure",text:"Failed to delete user!",type:"error"})}}return(f, r)=>(u(),B(M,{title:n(d),visible:t.visible,onClose:p},{default:x(()=>[e("fieldset",null,[j,i.userId==="#NEW#"?(u(),h("div",q,[e("label",G,o(f.$t("modals.useredit.identifier")),1),m(e("input",{"onUpdate:modelValue":r[0]||(r[0]= c=>s.value.Identifier=c),class:"form-control",placeholder:"The user id",type:"text"},null,512),[[g,s.value.Identifier]])])):$("",!0),e("div",K,[e("label",Y,o(f.$t("modals.useredit.source")),1),m(e("input",{"onUpdate:modelValue":r[1]||(r[1]= c=>s.value.Source=c),class:"form-control",disabled:"disabled",placeholder:"The user source",type:"text"},null,512),[[g,s.value.Source]])]),s.value.Source==="db"?(u(),h("div",J,[e("label",Q,o(f.$t("modals.useredit.password")),1),m(e("input",{"onUpdate:modelValue":r[2]||(r[2]= c=>s.value.Password=c),"aria-describedby":"passwordHelp",class:"form-control",placeholder:"Password",type:"text"},null,512),[[g,s.value.Password]]),i.userId!=="#NEW#"?(u(),h("small",R,"Leave this field blank to keep current password.")):$("",!0)])):$("",!0)]),e("fieldset",null,[X,e("div",Z,[e("label",ee,o(f.$t("modals.useredit.email")),1),m(e("input",{"onUpdate:modelValue":r[3]||(r[3]= c=>s.value.Email=c),class:"form-control",placeholder:"Email",type:"email"},null,512),[[g,s.value.Email]])]),e("div",se,[e("div",te,[e("label",le,o(f.$t("modals.useredit.firstname")),1),m(e("input",{"onUpdate:modelValue":r[4]||(r[4]= c=>s.value.Firstname=c),class:"form-control",placeholder:"Firstname",type:"text"},null,512),[[g,s.value.Firstname]])]),e("div",oe,[e("label",ae,o(f.$t("modals.useredit.lastname")),1),m(e("input",{"onUpdate:modelValue":r[5]||(r[5]= c=>s.value.Lastname=c),class:"form-control",placeholder:"Lastname",type:"text"},null,512),[[g,s.value.Lastname]])])]),e("div",ne,[e("div",ie,[e("label",re,o(f.$t("modals.useredit.phone")),1),m(e("input",{"onUpdate:modelValue":r[6]||(r[6]= c=>s.value.Phone=c),class:"form-control",placeholder:"Phone",type:"text"},null,512),[[g,s.value.Phone]])]),e("div",de,[e("label",ce,o(f.$t("modals.useredit.department")),1),m(e("input",{"onUpdate:modelValue":r[7]||(r[7]= c=>s.value.Department=c),class:"form-control",placeholder:"Department",type:"text"},null,512),[[g,s.value.Department]])])])]),e("fieldset",null,[ue,e("div",he,[e("label",pe,o(f.$t("modals.useredit.notes")),1),m(e("textarea",{"onUpdate:modelValue":r[8]||(r[8]= c=>s.value.Notes=c),class:"form-control",rows:"2"},null,512),[[g,s.value.Notes]])])]),e("fieldset",null,[fe,e("div",me,[m(e("input",{"onUpdate:modelValue":r[9]||(r[9]= c=>s.value.Disabled=c),class:"form-check-input",type:"checkbox"},null,512),[[V,s.value.Disabled]]),_e]),e("div",ve,[m(e("input",{"onUpdate:modelValue":r[10]||(r[10]= c=>s.value.IsAdmin=c),checked:"",class:"form-check-input",type:"checkbox"},null,512),[[V,s.value.IsAdmin]]),ge])])]),footer:x(()=>[e("div",be,[i.userId!=="#NEW#"?(u(),h("button",{key:0,class:"btn btn-danger me-1",type:"button",onClick:k(y,["prevent"])},"Delete",8,$e)):$("",!0)]),e("button",{class:"btn btn-primary me-1",type:"button",onClick:k(S,["prevent"])},"Save",8,ke),e("button",{class:"btn btn-secondary",type:"button",onClick:k(p,["prevent"])},"Discard",8,ye)]),_:1},8,["title","visible"]))}},Ce=e("ul",{class:"nav nav-tabs"},[e("li",{class:"nav-item"},[e("a",{class:"nav-link active","data-bs-toggle":"tab",href:"#user"},"User")]),e("li",{class:"nav-item"},[e("a",{class:"nav-link","data-bs-toggle":"tab",href:"#peers"},"Peers")])],-1),Ue={id:"interfaceTabs",class:"tab-content"},Ie={id:"user",class:"tab-pane fade active show"},we={class:"list-group list-group-flush"},Se={class:"list-group-item"},Fe={class:"table table-sm table-borderless device-status-table"},xe={class:"list-group-item"},De={class:"table table-sm table-borderless device-status-table"},Ee={id:"peers",class:"tab-pane fade"},Ne={key:0,class:"list-group list-group-flush"},Ve={class:"list-group-item"},ze={key:1,id:"peerTable",class:"table table-sm"},Le={scope:"col"},Ae={scope:"col"},Oe=e("th",{scope:"col"},null,-1),Be=["onClick"],Me={__name:"UserViewModal",props:{userId:String,visible:Boolean},emits:["close"],setup(t, {emit:l}){const i=t,{t:v}=A(),_=N(),a=U(()=>{let p=_.Find(i.userId);return p||{}}),d=U(()=>i.visible?v("users.view")+": "+a.value.Identifier:""),s=U(()=>_.Peers);O(()=>i.visible,async(p, S)=>{S===!1&&p===!0&&(console.log(a.value),await _.LoadUserPeers(a.value.Identifier))});function b(){l("close")}return(p, S)=>(u(),B(M,{title:n(d),visible:t.visible,onClose:b},{default:x(()=>[Ce,e("div",Ue,[e("div",Ie,[e("ul",we,[e("li",Se,[z(" User Information: "),e("table",Fe,[e("tbody",null,[e("tr",null,[e("td",null,o(p.$t("users.label.email"))+":",1),e("td",null,o(n(a).Email),1)]),e("tr",null,[e("td",null,o(p.$t("users.label.firstname"))+":",1),e("td",null,o(n(a).Firstname),1)]),e("tr",null,[e("td",null,o(p.$t("users.label.lastname"))+":",1),e("td",null,o(n(a).Lastname),1)]),e("tr",null,[e("td",null,o(p.$t("users.label.phone"))+":",1),e("td",null,o(n(a).Phone),1)]),e("tr",null,[e("td",null,o(p.$t("users.label.department"))+":",1),e("td",null,o(n(a).Department),1)])])])]),e("li",xe,[z(" Notes: "),e("table",De,[e("tbody",null,[e("tr",null,[e("td",null,o(n(a).Notes),1)])])])])])]),e("div",Ee,[n(s).length===0?(u(),h("ul",Ne,[e("li",Ve,o(p.$t("users.nopeers.message")),1)])):$("",!0),n(s).length!==0?(u(),h("table",ze,[e("thead",null,[e("tr",null,[e("th",Le,o(p.$t("user.peers.name")),1),e("th",Ae,o(p.$t("user.peers.ips")),1),Oe])]),e("tbody",null,[(u(!0),h(I,null,D(n(s), y=>(u(),h("tr",{key:y.Identifier},[e("td",null,o(y.DisplayName),1),e("td",null,[(u(!0),h(I,null,D(y.Addresses, f=>(u(),h("span",{key:f,class:"badge rounded-pill bg-light"},o(f),1))),128))])]))),128))])])):$("",!0)])])]),footer:x(()=>[e("button",{class:"btn btn-primary",type:"button",onClick:k(b,["prevent"])},"Close",8,Be)]),_:1},8,["title","visible"]))}},Te={class:"mt-4 row"},We={class:"col-12 col-lg-5"},He={class:"col-12 col-lg-4 text-lg-end"},je={class:"form-group d-inline"},qe={class:"input-group mb-3"},Ge=e("button",{class:"input-group-text btn btn-primary",title:"Search"},[e("i",{class:"fa-solid fa-search"})],-1),Ke={class:"col-12 col-lg-3 text-lg-end"},Ye=e("a",{class:"btn btn-primary",href:"#",title:"Send mail to selected users"},[e("i",{class:"fa fa-paper-plane"})],-1),Je=e("i",{class:"fa fa-plus me-1"},null,-1),Qe=e("i",{class:"fa fa-user"},null,-1),Re=[Je,Qe],Xe={class:"mt-2 table-responsive"},Ze={key:0},es={key:1,id:"userTable",class:"table table-sm"},ss=e("th",{scope:"col"},[e("input",{id:"flexCheckDefault",class:"form-check-input",title:"Select all",type:"checkbox",value:""})],-1),ts={scope:"col"},ls={scope:"col"},os={scope:"col"},as={scope:"col"},ns={class:"text-center",scope:"col"},is={class:"text-center",scope:"col"},rs={class:"text-center",scope:"col"},ds=e("th",{scope:"col"},null,-1),cs=e("th",{scope:"row"},[e("input",{id:"flexCheckDefault",class:"form-check-input",type:"checkbox",value:""})],-1),us={class:"text-center"},hs={class:"badge rounded-pill bg-light"},ps={class:"text-center"},fs={class:"text-center"},ms={key:0,class:"text-danger"},_s=e("i",{class:"fa fa-check-circle"},null,-1),vs=[_s],gs={key:1},bs=e("i",{class:"fa fa-circle-xmark"},null,-1),$s=[bs],ks={class:"text-center"},ys=["onClick"],Ps=e("i",{class:"fa-solid fa-magnifying-glass me-2"},null,-1),Cs=[Ps],Us=["onClick"],Is=e("i",{class:"fas fa-cog me-2"},null,-1),ws=[Is],Ss=e("hr",null,null,-1),Fs={class:"mt-3"},xs={class:"row"},Ds={class:"col-6"},Es={class:"pagination pagination-sm"},Ns=["onClick"],Vs={class:"col-6"},zs={class:"form-group row"},Ls={class:"col-sm-6 col-form-label text-end",for:"paginationSelector"},As={class:"col-sm-6"},Os=e("option",{value:"10"},"10",-1),Bs=e("option",{value:"25"},"25",-1),Ms=e("option",{value:"50"},"50",-1),Ts=e("option",{value:"100"},"100",-1),Ws={value:"999999999"},js={__name:"UserView",setup(t){const l=N(),i=E(""),v=E("");W(()=>{l.LoadUsers()});function _(a){a.Source==="db"?i.value=a.Identifier:w({title:"Forbidden",text:"You can not edit this user!",type:"error"})}return(a, d)=>(u(),h(I,null,[L(Pe,{userId:i.value,visible:i.value!=="",onClose:d[0]||(d[0]= s=>i.value="")},null,8,["userId","visible"]),L(Me,{userId:v.value,visible:v.value!=="",onClose:d[1]||(d[1]= s=>v.value="")},null,8,["userId","visible"]),e("div",Te,[e("div",We,[e("h1",null,o(a.$t("user.h1")),1)]),e("div",He,[e("div",je,[e("div",qe,[m(e("input",{"onUpdate:modelValue":d[2]||(d[2]= s=>n(l).filter=s),class:"form-control",placeholder:"Search...",type:"text",onKeyup:d[3]||(d[3]=(...s)=>n(l).afterPageSizeChange&&n(l).afterPageSizeChange(...s))},null,544),[[g,n(l).filter]]),Ge])])]),e("div",Ke,[Ye,e("a",{class:"btn btn-primary ms-2",href:"#",title:"Add a user",onClick:d[4]||(d[4]=k(s=>i.value="#NEW#",["prevent"]))},Re)])]),e("div",Xe,[n(l).Count===0?(u(),h("div",Ze,[e("h4",null,o(a.$t("users.noUsers.h4")),1),e("p",null,o(a.$t("users.noUsers.message")),1)])):$("",!0),n(l).Count!==0?(u(),h("table",es,[e("thead",null,[e("tr",null,[ss,e("th",ts,o(a.$t("user.id")),1),e("th",ls,o(a.$t("user.email")),1),e("th",os,o(a.$t("user.firstname")),1),e("th",as,o(a.$t("user.lastname")),1),e("th",ns,o(a.$t("user.source")),1),e("th",is,o(a.$t("user.peers")),1),e("th",rs,o(a.$t("user.admin")),1),ds])]),e("tbody",null,[(u(!0),h(I,null,D(n(l).FilteredAndPaged, s=>(u(),h("tr",{key:s.Identifier},[cs,e("td",null,o(s.Identifier),1),e("td",null,o(s.Email),1),e("td",null,o(s.Firstname),1),e("td",null,o(s.Lastname),1),e("td",us,[e("span",hs,o(s.Source),1)]),e("td",ps,o(s.PeerCount),1),e("td",fs,[s.IsAdmin?(u(),h("span",ms,vs)):(u(),h("span",gs,$s))]),e("td",ks,[e("a",{href:"#",title:"Show user",onClick:k(b=>v.value=s.Identifier,["prevent"])},Cs,8,ys),e("a",{class:F({disabled:s.Source!=="db"}),href:"#",title:"Edit user",onClick:k(b=>_(s),["prevent"])},ws,10,Us)])]))),128))])])):$("",!0)]),Ss,e("div",Fs,[e("div",xs,[e("div",Ds,[e("ul",Es,[e("li",{class:F([{disabled:n(l).pageOffset===0},"page-item"])},[e("a",{class:"page-link",onClick:d[5]||(d[5]=(...s)=>n(l).previousPage&&n(l).previousPage(...s))},"«")],2),(u(!0),h(I,null,D(n(l).pages, s=>(u(),h("li",{key:s,class:F([{active:n(l).currentPage===s},"page-item"])},[e("a",{class:"page-link",onClick: b=>n(l).gotoPage(s)},o(s),9,Ns)],2))),128)),e("li",{class:F([{disabled:!n(l).hasNextPage},"page-item"])},[e("a",{class:"page-link",onClick:d[6]||(d[6]=(...s)=>n(l).nextPage&&n(l).nextPage(...s))},"»")],2)])]),e("div",Vs,[e("div",zs,[e("label",Ls,o(a.$t("interfaces.pagination.size"))+":",1),e("div",As,[m(e("select",{"onUpdate:modelValue":d[7]||(d[7]= s=>n(l).pageSize=s),class:"form-select",onClick:d[8]||(d[8]= s=>n(l).afterPageSizeChange())},[Os,Bs,Ms,Ts,e("option",Ws,o(a.$t("interfaces.pagination.all")),1)],512),[[H,n(l).pageSize,void 0,{number:!0}]])])])])])])],64))}};export{js as default}; diff --git a/internal/ports/api/core/frontend-dist/assets/ac-7f066d2b.svg b/internal/app/api/core/frontend-dist/assets/ac-7f066d2b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ac-7f066d2b.svg rename to internal/app/api/core/frontend-dist/assets/ac-7f066d2b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ac-a4ddad70.svg b/internal/app/api/core/frontend-dist/assets/ac-a4ddad70.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ac-a4ddad70.svg rename to internal/app/api/core/frontend-dist/assets/ac-a4ddad70.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ad-399354a9.svg b/internal/app/api/core/frontend-dist/assets/ad-399354a9.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ad-399354a9.svg rename to internal/app/api/core/frontend-dist/assets/ad-399354a9.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ad-e411c81d.svg b/internal/app/api/core/frontend-dist/assets/ad-e411c81d.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ad-e411c81d.svg rename to internal/app/api/core/frontend-dist/assets/ad-e411c81d.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ae-534fefed.svg b/internal/app/api/core/frontend-dist/assets/ae-534fefed.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ae-534fefed.svg rename to internal/app/api/core/frontend-dist/assets/ae-534fefed.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ae-e646ea13.svg b/internal/app/api/core/frontend-dist/assets/ae-e646ea13.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ae-e646ea13.svg rename to internal/app/api/core/frontend-dist/assets/ae-e646ea13.svg diff --git a/internal/ports/api/core/frontend-dist/assets/af-318f28f1.svg b/internal/app/api/core/frontend-dist/assets/af-318f28f1.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/af-318f28f1.svg rename to internal/app/api/core/frontend-dist/assets/af-318f28f1.svg diff --git a/internal/ports/api/core/frontend-dist/assets/af-6c420329.svg b/internal/app/api/core/frontend-dist/assets/af-6c420329.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/af-6c420329.svg rename to internal/app/api/core/frontend-dist/assets/af-6c420329.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ag-2760f340.svg b/internal/app/api/core/frontend-dist/assets/ag-2760f340.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ag-2760f340.svg rename to internal/app/api/core/frontend-dist/assets/ag-2760f340.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ag-7cc7d9ec.svg b/internal/app/api/core/frontend-dist/assets/ag-7cc7d9ec.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ag-7cc7d9ec.svg rename to internal/app/api/core/frontend-dist/assets/ag-7cc7d9ec.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ai-2113432b.svg b/internal/app/api/core/frontend-dist/assets/ai-2113432b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ai-2113432b.svg rename to internal/app/api/core/frontend-dist/assets/ai-2113432b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ai-61c43adb.svg b/internal/app/api/core/frontend-dist/assets/ai-61c43adb.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ai-61c43adb.svg rename to internal/app/api/core/frontend-dist/assets/ai-61c43adb.svg diff --git a/internal/ports/api/core/frontend-dist/assets/al-2253bcd8.svg b/internal/app/api/core/frontend-dist/assets/al-2253bcd8.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/al-2253bcd8.svg rename to internal/app/api/core/frontend-dist/assets/al-2253bcd8.svg diff --git a/internal/ports/api/core/frontend-dist/assets/al-f9b79f25.svg b/internal/app/api/core/frontend-dist/assets/al-f9b79f25.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/al-f9b79f25.svg rename to internal/app/api/core/frontend-dist/assets/al-f9b79f25.svg diff --git a/internal/ports/api/core/frontend-dist/assets/am-57edcffa.svg b/internal/app/api/core/frontend-dist/assets/am-57edcffa.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/am-57edcffa.svg rename to internal/app/api/core/frontend-dist/assets/am-57edcffa.svg diff --git a/internal/ports/api/core/frontend-dist/assets/am-efb6cdaa.svg b/internal/app/api/core/frontend-dist/assets/am-efb6cdaa.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/am-efb6cdaa.svg rename to internal/app/api/core/frontend-dist/assets/am-efb6cdaa.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ao-3c52ff53.svg b/internal/app/api/core/frontend-dist/assets/ao-3c52ff53.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ao-3c52ff53.svg rename to internal/app/api/core/frontend-dist/assets/ao-3c52ff53.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ao-a296c39c.svg b/internal/app/api/core/frontend-dist/assets/ao-a296c39c.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ao-a296c39c.svg rename to internal/app/api/core/frontend-dist/assets/ao-a296c39c.svg diff --git a/internal/ports/api/core/frontend-dist/assets/aq-454424bf.svg b/internal/app/api/core/frontend-dist/assets/aq-454424bf.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/aq-454424bf.svg rename to internal/app/api/core/frontend-dist/assets/aq-454424bf.svg diff --git a/internal/ports/api/core/frontend-dist/assets/aq-733794b7.svg b/internal/app/api/core/frontend-dist/assets/aq-733794b7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/aq-733794b7.svg rename to internal/app/api/core/frontend-dist/assets/aq-733794b7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ar-49a0084b.svg b/internal/app/api/core/frontend-dist/assets/ar-49a0084b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ar-49a0084b.svg rename to internal/app/api/core/frontend-dist/assets/ar-49a0084b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ar-92dd89b1.svg b/internal/app/api/core/frontend-dist/assets/ar-92dd89b1.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ar-92dd89b1.svg rename to internal/app/api/core/frontend-dist/assets/ar-92dd89b1.svg diff --git a/internal/ports/api/core/frontend-dist/assets/as-0af12c4a.svg b/internal/app/api/core/frontend-dist/assets/as-0af12c4a.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/as-0af12c4a.svg rename to internal/app/api/core/frontend-dist/assets/as-0af12c4a.svg diff --git a/internal/ports/api/core/frontend-dist/assets/as-a9ea837d.svg b/internal/app/api/core/frontend-dist/assets/as-a9ea837d.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/as-a9ea837d.svg rename to internal/app/api/core/frontend-dist/assets/as-a9ea837d.svg diff --git a/internal/ports/api/core/frontend-dist/assets/at-2754ed2f.svg b/internal/app/api/core/frontend-dist/assets/at-2754ed2f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/at-2754ed2f.svg rename to internal/app/api/core/frontend-dist/assets/at-2754ed2f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/at-9152f136.svg b/internal/app/api/core/frontend-dist/assets/at-9152f136.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/at-9152f136.svg rename to internal/app/api/core/frontend-dist/assets/at-9152f136.svg diff --git a/internal/ports/api/core/frontend-dist/assets/au-01aa7963.svg b/internal/app/api/core/frontend-dist/assets/au-01aa7963.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/au-01aa7963.svg rename to internal/app/api/core/frontend-dist/assets/au-01aa7963.svg diff --git a/internal/ports/api/core/frontend-dist/assets/au-6cf0b0da.svg b/internal/app/api/core/frontend-dist/assets/au-6cf0b0da.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/au-6cf0b0da.svg rename to internal/app/api/core/frontend-dist/assets/au-6cf0b0da.svg diff --git a/internal/ports/api/core/frontend-dist/assets/aw-0379172e.svg b/internal/app/api/core/frontend-dist/assets/aw-0379172e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/aw-0379172e.svg rename to internal/app/api/core/frontend-dist/assets/aw-0379172e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/aw-5e136f5b.svg b/internal/app/api/core/frontend-dist/assets/aw-5e136f5b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/aw-5e136f5b.svg rename to internal/app/api/core/frontend-dist/assets/aw-5e136f5b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ax-140f94bb.svg b/internal/app/api/core/frontend-dist/assets/ax-140f94bb.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ax-140f94bb.svg rename to internal/app/api/core/frontend-dist/assets/ax-140f94bb.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ax-e2162713.svg b/internal/app/api/core/frontend-dist/assets/ax-e2162713.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ax-e2162713.svg rename to internal/app/api/core/frontend-dist/assets/ax-e2162713.svg diff --git a/internal/ports/api/core/frontend-dist/assets/az-b942e12d.svg b/internal/app/api/core/frontend-dist/assets/az-b942e12d.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/az-b942e12d.svg rename to internal/app/api/core/frontend-dist/assets/az-b942e12d.svg diff --git a/internal/ports/api/core/frontend-dist/assets/az-fef5c465.svg b/internal/app/api/core/frontend-dist/assets/az-fef5c465.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/az-fef5c465.svg rename to internal/app/api/core/frontend-dist/assets/az-fef5c465.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ba-7fe2acc6.svg b/internal/app/api/core/frontend-dist/assets/ba-7fe2acc6.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ba-7fe2acc6.svg rename to internal/app/api/core/frontend-dist/assets/ba-7fe2acc6.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ba-f7fbd614.svg b/internal/app/api/core/frontend-dist/assets/ba-f7fbd614.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ba-f7fbd614.svg rename to internal/app/api/core/frontend-dist/assets/ba-f7fbd614.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bb-20bd0c90.svg b/internal/app/api/core/frontend-dist/assets/bb-20bd0c90.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bb-20bd0c90.svg rename to internal/app/api/core/frontend-dist/assets/bb-20bd0c90.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bb-beaf3ae6.svg b/internal/app/api/core/frontend-dist/assets/bb-beaf3ae6.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bb-beaf3ae6.svg rename to internal/app/api/core/frontend-dist/assets/bb-beaf3ae6.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bd-1aabb4a7.svg b/internal/app/api/core/frontend-dist/assets/bd-1aabb4a7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bd-1aabb4a7.svg rename to internal/app/api/core/frontend-dist/assets/bd-1aabb4a7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bd-90f8f20e.svg b/internal/app/api/core/frontend-dist/assets/bd-90f8f20e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bd-90f8f20e.svg rename to internal/app/api/core/frontend-dist/assets/bd-90f8f20e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/be-42f09ed6.svg b/internal/app/api/core/frontend-dist/assets/be-42f09ed6.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/be-42f09ed6.svg rename to internal/app/api/core/frontend-dist/assets/be-42f09ed6.svg diff --git a/internal/ports/api/core/frontend-dist/assets/be-a2f62b54.svg b/internal/app/api/core/frontend-dist/assets/be-a2f62b54.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/be-a2f62b54.svg rename to internal/app/api/core/frontend-dist/assets/be-a2f62b54.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bf-606b17ad.svg b/internal/app/api/core/frontend-dist/assets/bf-606b17ad.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bf-606b17ad.svg rename to internal/app/api/core/frontend-dist/assets/bf-606b17ad.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bf-62cdc2bd.svg b/internal/app/api/core/frontend-dist/assets/bf-62cdc2bd.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bf-62cdc2bd.svg rename to internal/app/api/core/frontend-dist/assets/bf-62cdc2bd.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bg-40e29b66.svg b/internal/app/api/core/frontend-dist/assets/bg-40e29b66.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bg-40e29b66.svg rename to internal/app/api/core/frontend-dist/assets/bg-40e29b66.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bg-a2282477.svg b/internal/app/api/core/frontend-dist/assets/bg-a2282477.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bg-a2282477.svg rename to internal/app/api/core/frontend-dist/assets/bg-a2282477.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bh-102fe27e.svg b/internal/app/api/core/frontend-dist/assets/bh-102fe27e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bh-102fe27e.svg rename to internal/app/api/core/frontend-dist/assets/bh-102fe27e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bh-7a519f58.svg b/internal/app/api/core/frontend-dist/assets/bh-7a519f58.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bh-7a519f58.svg rename to internal/app/api/core/frontend-dist/assets/bh-7a519f58.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bi-3e1ff149.svg b/internal/app/api/core/frontend-dist/assets/bi-3e1ff149.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bi-3e1ff149.svg rename to internal/app/api/core/frontend-dist/assets/bi-3e1ff149.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bi-46ceb5f8.svg b/internal/app/api/core/frontend-dist/assets/bi-46ceb5f8.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bi-46ceb5f8.svg rename to internal/app/api/core/frontend-dist/assets/bi-46ceb5f8.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bj-6f5043b4.svg b/internal/app/api/core/frontend-dist/assets/bj-6f5043b4.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bj-6f5043b4.svg rename to internal/app/api/core/frontend-dist/assets/bj-6f5043b4.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bj-ab7b5a85.svg b/internal/app/api/core/frontend-dist/assets/bj-ab7b5a85.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bj-ab7b5a85.svg rename to internal/app/api/core/frontend-dist/assets/bj-ab7b5a85.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bl-025f596f.svg b/internal/app/api/core/frontend-dist/assets/bl-025f596f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bl-025f596f.svg rename to internal/app/api/core/frontend-dist/assets/bl-025f596f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bl-5da1d4f8.svg b/internal/app/api/core/frontend-dist/assets/bl-5da1d4f8.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bl-5da1d4f8.svg rename to internal/app/api/core/frontend-dist/assets/bl-5da1d4f8.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bm-d0a9f672.svg b/internal/app/api/core/frontend-dist/assets/bm-d0a9f672.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bm-d0a9f672.svg rename to internal/app/api/core/frontend-dist/assets/bm-d0a9f672.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bm-def86a14.svg b/internal/app/api/core/frontend-dist/assets/bm-def86a14.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bm-def86a14.svg rename to internal/app/api/core/frontend-dist/assets/bm-def86a14.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bn-07740542.svg b/internal/app/api/core/frontend-dist/assets/bn-07740542.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bn-07740542.svg rename to internal/app/api/core/frontend-dist/assets/bn-07740542.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bn-db17f97a.svg b/internal/app/api/core/frontend-dist/assets/bn-db17f97a.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bn-db17f97a.svg rename to internal/app/api/core/frontend-dist/assets/bn-db17f97a.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bo-4806a8c7.svg b/internal/app/api/core/frontend-dist/assets/bo-4806a8c7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bo-4806a8c7.svg rename to internal/app/api/core/frontend-dist/assets/bo-4806a8c7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bo-63594b20.svg b/internal/app/api/core/frontend-dist/assets/bo-63594b20.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bo-63594b20.svg rename to internal/app/api/core/frontend-dist/assets/bo-63594b20.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bq-23881e6c.svg b/internal/app/api/core/frontend-dist/assets/bq-23881e6c.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bq-23881e6c.svg rename to internal/app/api/core/frontend-dist/assets/bq-23881e6c.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bq-83723941.svg b/internal/app/api/core/frontend-dist/assets/bq-83723941.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bq-83723941.svg rename to internal/app/api/core/frontend-dist/assets/bq-83723941.svg diff --git a/internal/ports/api/core/frontend-dist/assets/br-ce7e334e.svg b/internal/app/api/core/frontend-dist/assets/br-ce7e334e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/br-ce7e334e.svg rename to internal/app/api/core/frontend-dist/assets/br-ce7e334e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/br-fc872e71.svg b/internal/app/api/core/frontend-dist/assets/br-fc872e71.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/br-fc872e71.svg rename to internal/app/api/core/frontend-dist/assets/br-fc872e71.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bs-90305318.svg b/internal/app/api/core/frontend-dist/assets/bs-90305318.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bs-90305318.svg rename to internal/app/api/core/frontend-dist/assets/bs-90305318.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bs-ee46721d.svg b/internal/app/api/core/frontend-dist/assets/bs-ee46721d.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bs-ee46721d.svg rename to internal/app/api/core/frontend-dist/assets/bs-ee46721d.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bt-84e84171.svg b/internal/app/api/core/frontend-dist/assets/bt-84e84171.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bt-84e84171.svg rename to internal/app/api/core/frontend-dist/assets/bt-84e84171.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bt-dc7fe8fa.svg b/internal/app/api/core/frontend-dist/assets/bt-dc7fe8fa.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bt-dc7fe8fa.svg rename to internal/app/api/core/frontend-dist/assets/bt-dc7fe8fa.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bv-03917bba.svg b/internal/app/api/core/frontend-dist/assets/bv-03917bba.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bv-03917bba.svg rename to internal/app/api/core/frontend-dist/assets/bv-03917bba.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bv-091fb966.svg b/internal/app/api/core/frontend-dist/assets/bv-091fb966.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bv-091fb966.svg rename to internal/app/api/core/frontend-dist/assets/bv-091fb966.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bw-1fc9322c.svg b/internal/app/api/core/frontend-dist/assets/bw-1fc9322c.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bw-1fc9322c.svg rename to internal/app/api/core/frontend-dist/assets/bw-1fc9322c.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bw-e1e15926.svg b/internal/app/api/core/frontend-dist/assets/bw-e1e15926.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bw-e1e15926.svg rename to internal/app/api/core/frontend-dist/assets/bw-e1e15926.svg diff --git a/internal/ports/api/core/frontend-dist/assets/by-b0ac20fe.svg b/internal/app/api/core/frontend-dist/assets/by-b0ac20fe.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/by-b0ac20fe.svg rename to internal/app/api/core/frontend-dist/assets/by-b0ac20fe.svg diff --git a/internal/ports/api/core/frontend-dist/assets/by-c74090d5.svg b/internal/app/api/core/frontend-dist/assets/by-c74090d5.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/by-c74090d5.svg rename to internal/app/api/core/frontend-dist/assets/by-c74090d5.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bz-4085bcd0.svg b/internal/app/api/core/frontend-dist/assets/bz-4085bcd0.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bz-4085bcd0.svg rename to internal/app/api/core/frontend-dist/assets/bz-4085bcd0.svg diff --git a/internal/ports/api/core/frontend-dist/assets/bz-c57817a5.svg b/internal/app/api/core/frontend-dist/assets/bz-c57817a5.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/bz-c57817a5.svg rename to internal/app/api/core/frontend-dist/assets/bz-c57817a5.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ca-5e8736c4.svg b/internal/app/api/core/frontend-dist/assets/ca-5e8736c4.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ca-5e8736c4.svg rename to internal/app/api/core/frontend-dist/assets/ca-5e8736c4.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ca-73bd9657.svg b/internal/app/api/core/frontend-dist/assets/ca-73bd9657.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ca-73bd9657.svg rename to internal/app/api/core/frontend-dist/assets/ca-73bd9657.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cc-eec3b923.svg b/internal/app/api/core/frontend-dist/assets/cc-eec3b923.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cc-eec3b923.svg rename to internal/app/api/core/frontend-dist/assets/cc-eec3b923.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cc-f4e9b00e.svg b/internal/app/api/core/frontend-dist/assets/cc-f4e9b00e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cc-f4e9b00e.svg rename to internal/app/api/core/frontend-dist/assets/cc-f4e9b00e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cd-23f049df.svg b/internal/app/api/core/frontend-dist/assets/cd-23f049df.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cd-23f049df.svg rename to internal/app/api/core/frontend-dist/assets/cd-23f049df.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cd-620c7263.svg b/internal/app/api/core/frontend-dist/assets/cd-620c7263.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cd-620c7263.svg rename to internal/app/api/core/frontend-dist/assets/cd-620c7263.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cf-3c6b6c0b.svg b/internal/app/api/core/frontend-dist/assets/cf-3c6b6c0b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cf-3c6b6c0b.svg rename to internal/app/api/core/frontend-dist/assets/cf-3c6b6c0b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cf-cd11e360.svg b/internal/app/api/core/frontend-dist/assets/cf-cd11e360.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cf-cd11e360.svg rename to internal/app/api/core/frontend-dist/assets/cf-cd11e360.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cg-66f98bc1.svg b/internal/app/api/core/frontend-dist/assets/cg-66f98bc1.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cg-66f98bc1.svg rename to internal/app/api/core/frontend-dist/assets/cg-66f98bc1.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cg-f8467d04.svg b/internal/app/api/core/frontend-dist/assets/cg-f8467d04.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cg-f8467d04.svg rename to internal/app/api/core/frontend-dist/assets/cg-f8467d04.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ch-ac676cd3.svg b/internal/app/api/core/frontend-dist/assets/ch-ac676cd3.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ch-ac676cd3.svg rename to internal/app/api/core/frontend-dist/assets/ch-ac676cd3.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ch-be4b8257.svg b/internal/app/api/core/frontend-dist/assets/ch-be4b8257.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ch-be4b8257.svg rename to internal/app/api/core/frontend-dist/assets/ch-be4b8257.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ci-4ecfea70.svg b/internal/app/api/core/frontend-dist/assets/ci-4ecfea70.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ci-4ecfea70.svg rename to internal/app/api/core/frontend-dist/assets/ci-4ecfea70.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ci-c3f20b8e.svg b/internal/app/api/core/frontend-dist/assets/ci-c3f20b8e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ci-c3f20b8e.svg rename to internal/app/api/core/frontend-dist/assets/ci-c3f20b8e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ck-b17c039f.svg b/internal/app/api/core/frontend-dist/assets/ck-b17c039f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ck-b17c039f.svg rename to internal/app/api/core/frontend-dist/assets/ck-b17c039f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ck-e5457495.svg b/internal/app/api/core/frontend-dist/assets/ck-e5457495.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ck-e5457495.svg rename to internal/app/api/core/frontend-dist/assets/ck-e5457495.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cl-bde5c7c2.svg b/internal/app/api/core/frontend-dist/assets/cl-bde5c7c2.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cl-bde5c7c2.svg rename to internal/app/api/core/frontend-dist/assets/cl-bde5c7c2.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cl-dc9bc06f.svg b/internal/app/api/core/frontend-dist/assets/cl-dc9bc06f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cl-dc9bc06f.svg rename to internal/app/api/core/frontend-dist/assets/cl-dc9bc06f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cm-db88be4b.svg b/internal/app/api/core/frontend-dist/assets/cm-db88be4b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cm-db88be4b.svg rename to internal/app/api/core/frontend-dist/assets/cm-db88be4b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cm-f351617f.svg b/internal/app/api/core/frontend-dist/assets/cm-f351617f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cm-f351617f.svg rename to internal/app/api/core/frontend-dist/assets/cm-f351617f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cn-9f7f1ab6.svg b/internal/app/api/core/frontend-dist/assets/cn-9f7f1ab6.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cn-9f7f1ab6.svg rename to internal/app/api/core/frontend-dist/assets/cn-9f7f1ab6.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cn-c1f22841.svg b/internal/app/api/core/frontend-dist/assets/cn-c1f22841.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cn-c1f22841.svg rename to internal/app/api/core/frontend-dist/assets/cn-c1f22841.svg diff --git a/internal/ports/api/core/frontend-dist/assets/co-596558a2.svg b/internal/app/api/core/frontend-dist/assets/co-596558a2.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/co-596558a2.svg rename to internal/app/api/core/frontend-dist/assets/co-596558a2.svg diff --git a/internal/ports/api/core/frontend-dist/assets/co-6bab3c96.svg b/internal/app/api/core/frontend-dist/assets/co-6bab3c96.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/co-6bab3c96.svg rename to internal/app/api/core/frontend-dist/assets/co-6bab3c96.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cp-582fc375.svg b/internal/app/api/core/frontend-dist/assets/cp-582fc375.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cp-582fc375.svg rename to internal/app/api/core/frontend-dist/assets/cp-582fc375.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cp-907b4b54.svg b/internal/app/api/core/frontend-dist/assets/cp-907b4b54.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cp-907b4b54.svg rename to internal/app/api/core/frontend-dist/assets/cp-907b4b54.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cr-4775ef01.svg b/internal/app/api/core/frontend-dist/assets/cr-4775ef01.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cr-4775ef01.svg rename to internal/app/api/core/frontend-dist/assets/cr-4775ef01.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cr-b70b33c4.svg b/internal/app/api/core/frontend-dist/assets/cr-b70b33c4.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cr-b70b33c4.svg rename to internal/app/api/core/frontend-dist/assets/cr-b70b33c4.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cu-5bd635ae.svg b/internal/app/api/core/frontend-dist/assets/cu-5bd635ae.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cu-5bd635ae.svg rename to internal/app/api/core/frontend-dist/assets/cu-5bd635ae.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cu-f7f44c3e.svg b/internal/app/api/core/frontend-dist/assets/cu-f7f44c3e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cu-f7f44c3e.svg rename to internal/app/api/core/frontend-dist/assets/cu-f7f44c3e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cv-237307fe.svg b/internal/app/api/core/frontend-dist/assets/cv-237307fe.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cv-237307fe.svg rename to internal/app/api/core/frontend-dist/assets/cv-237307fe.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cv-a855505a.svg b/internal/app/api/core/frontend-dist/assets/cv-a855505a.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cv-a855505a.svg rename to internal/app/api/core/frontend-dist/assets/cv-a855505a.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cw-929063b2.svg b/internal/app/api/core/frontend-dist/assets/cw-929063b2.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cw-929063b2.svg rename to internal/app/api/core/frontend-dist/assets/cw-929063b2.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cw-a689736d.svg b/internal/app/api/core/frontend-dist/assets/cw-a689736d.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cw-a689736d.svg rename to internal/app/api/core/frontend-dist/assets/cw-a689736d.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cx-81387568.svg b/internal/app/api/core/frontend-dist/assets/cx-81387568.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cx-81387568.svg rename to internal/app/api/core/frontend-dist/assets/cx-81387568.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cx-8c09357b.svg b/internal/app/api/core/frontend-dist/assets/cx-8c09357b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cx-8c09357b.svg rename to internal/app/api/core/frontend-dist/assets/cx-8c09357b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cy-aa9b4c30.svg b/internal/app/api/core/frontend-dist/assets/cy-aa9b4c30.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cy-aa9b4c30.svg rename to internal/app/api/core/frontend-dist/assets/cy-aa9b4c30.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cy-ed929efd.svg b/internal/app/api/core/frontend-dist/assets/cy-ed929efd.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cy-ed929efd.svg rename to internal/app/api/core/frontend-dist/assets/cy-ed929efd.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cz-5a462b5f.svg b/internal/app/api/core/frontend-dist/assets/cz-5a462b5f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cz-5a462b5f.svg rename to internal/app/api/core/frontend-dist/assets/cz-5a462b5f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/cz-d601fcc2.svg b/internal/app/api/core/frontend-dist/assets/cz-d601fcc2.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/cz-d601fcc2.svg rename to internal/app/api/core/frontend-dist/assets/cz-d601fcc2.svg diff --git a/internal/ports/api/core/frontend-dist/assets/de-7318c9aa.svg b/internal/app/api/core/frontend-dist/assets/de-7318c9aa.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/de-7318c9aa.svg rename to internal/app/api/core/frontend-dist/assets/de-7318c9aa.svg diff --git a/internal/ports/api/core/frontend-dist/assets/de-d5f40046.svg b/internal/app/api/core/frontend-dist/assets/de-d5f40046.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/de-d5f40046.svg rename to internal/app/api/core/frontend-dist/assets/de-d5f40046.svg diff --git a/internal/ports/api/core/frontend-dist/assets/dg-347ef660.svg b/internal/app/api/core/frontend-dist/assets/dg-347ef660.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/dg-347ef660.svg rename to internal/app/api/core/frontend-dist/assets/dg-347ef660.svg diff --git a/internal/ports/api/core/frontend-dist/assets/dg-aa35d3b2.svg b/internal/app/api/core/frontend-dist/assets/dg-aa35d3b2.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/dg-aa35d3b2.svg rename to internal/app/api/core/frontend-dist/assets/dg-aa35d3b2.svg diff --git a/internal/ports/api/core/frontend-dist/assets/dj-0a60922e.svg b/internal/app/api/core/frontend-dist/assets/dj-0a60922e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/dj-0a60922e.svg rename to internal/app/api/core/frontend-dist/assets/dj-0a60922e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/dj-7baede08.svg b/internal/app/api/core/frontend-dist/assets/dj-7baede08.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/dj-7baede08.svg rename to internal/app/api/core/frontend-dist/assets/dj-7baede08.svg diff --git a/internal/ports/api/core/frontend-dist/assets/dk-4d7c9c44.svg b/internal/app/api/core/frontend-dist/assets/dk-4d7c9c44.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/dk-4d7c9c44.svg rename to internal/app/api/core/frontend-dist/assets/dk-4d7c9c44.svg diff --git a/internal/ports/api/core/frontend-dist/assets/dk-d2847c0b.svg b/internal/app/api/core/frontend-dist/assets/dk-d2847c0b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/dk-d2847c0b.svg rename to internal/app/api/core/frontend-dist/assets/dk-d2847c0b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/dm-4ac56c6b.svg b/internal/app/api/core/frontend-dist/assets/dm-4ac56c6b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/dm-4ac56c6b.svg rename to internal/app/api/core/frontend-dist/assets/dm-4ac56c6b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/dm-5758b806.svg b/internal/app/api/core/frontend-dist/assets/dm-5758b806.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/dm-5758b806.svg rename to internal/app/api/core/frontend-dist/assets/dm-5758b806.svg diff --git a/internal/ports/api/core/frontend-dist/assets/do-6722b711.svg b/internal/app/api/core/frontend-dist/assets/do-6722b711.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/do-6722b711.svg rename to internal/app/api/core/frontend-dist/assets/do-6722b711.svg diff --git a/internal/ports/api/core/frontend-dist/assets/do-d0790bb3.svg b/internal/app/api/core/frontend-dist/assets/do-d0790bb3.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/do-d0790bb3.svg rename to internal/app/api/core/frontend-dist/assets/do-d0790bb3.svg diff --git a/internal/ports/api/core/frontend-dist/assets/dz-73f56cc7.svg b/internal/app/api/core/frontend-dist/assets/dz-73f56cc7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/dz-73f56cc7.svg rename to internal/app/api/core/frontend-dist/assets/dz-73f56cc7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/dz-9ea0cf93.svg b/internal/app/api/core/frontend-dist/assets/dz-9ea0cf93.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/dz-9ea0cf93.svg rename to internal/app/api/core/frontend-dist/assets/dz-9ea0cf93.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ea-bb4ff4a8.svg b/internal/app/api/core/frontend-dist/assets/ea-bb4ff4a8.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ea-bb4ff4a8.svg rename to internal/app/api/core/frontend-dist/assets/ea-bb4ff4a8.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ea-e86d317d.svg b/internal/app/api/core/frontend-dist/assets/ea-e86d317d.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ea-e86d317d.svg rename to internal/app/api/core/frontend-dist/assets/ea-e86d317d.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ec-73be1a4b.svg b/internal/app/api/core/frontend-dist/assets/ec-73be1a4b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ec-73be1a4b.svg rename to internal/app/api/core/frontend-dist/assets/ec-73be1a4b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ec-c1196d0f.svg b/internal/app/api/core/frontend-dist/assets/ec-c1196d0f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ec-c1196d0f.svg rename to internal/app/api/core/frontend-dist/assets/ec-c1196d0f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ee-1c30ac2c.svg b/internal/app/api/core/frontend-dist/assets/ee-1c30ac2c.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ee-1c30ac2c.svg rename to internal/app/api/core/frontend-dist/assets/ee-1c30ac2c.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ee-733a082e.svg b/internal/app/api/core/frontend-dist/assets/ee-733a082e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ee-733a082e.svg rename to internal/app/api/core/frontend-dist/assets/ee-733a082e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/eg-60288e26.svg b/internal/app/api/core/frontend-dist/assets/eg-60288e26.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/eg-60288e26.svg rename to internal/app/api/core/frontend-dist/assets/eg-60288e26.svg diff --git a/internal/ports/api/core/frontend-dist/assets/eg-bc19c9ba.svg b/internal/app/api/core/frontend-dist/assets/eg-bc19c9ba.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/eg-bc19c9ba.svg rename to internal/app/api/core/frontend-dist/assets/eg-bc19c9ba.svg diff --git a/internal/ports/api/core/frontend-dist/assets/eh-5661bb32.svg b/internal/app/api/core/frontend-dist/assets/eh-5661bb32.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/eh-5661bb32.svg rename to internal/app/api/core/frontend-dist/assets/eh-5661bb32.svg diff --git a/internal/ports/api/core/frontend-dist/assets/eh-cd0c4d05.svg b/internal/app/api/core/frontend-dist/assets/eh-cd0c4d05.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/eh-cd0c4d05.svg rename to internal/app/api/core/frontend-dist/assets/eh-cd0c4d05.svg diff --git a/internal/ports/api/core/frontend-dist/assets/er-21cdc1d1.svg b/internal/app/api/core/frontend-dist/assets/er-21cdc1d1.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/er-21cdc1d1.svg rename to internal/app/api/core/frontend-dist/assets/er-21cdc1d1.svg diff --git a/internal/ports/api/core/frontend-dist/assets/er-6e90ebb6.svg b/internal/app/api/core/frontend-dist/assets/er-6e90ebb6.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/er-6e90ebb6.svg rename to internal/app/api/core/frontend-dist/assets/er-6e90ebb6.svg diff --git a/internal/ports/api/core/frontend-dist/assets/es-6fe80291.svg b/internal/app/api/core/frontend-dist/assets/es-6fe80291.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/es-6fe80291.svg rename to internal/app/api/core/frontend-dist/assets/es-6fe80291.svg diff --git a/internal/ports/api/core/frontend-dist/assets/es-ct-11229703.svg b/internal/app/api/core/frontend-dist/assets/es-ct-11229703.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/es-ct-11229703.svg rename to internal/app/api/core/frontend-dist/assets/es-ct-11229703.svg diff --git a/internal/ports/api/core/frontend-dist/assets/es-ct-95f4033c.svg b/internal/app/api/core/frontend-dist/assets/es-ct-95f4033c.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/es-ct-95f4033c.svg rename to internal/app/api/core/frontend-dist/assets/es-ct-95f4033c.svg diff --git a/internal/ports/api/core/frontend-dist/assets/es-edd3ba17.svg b/internal/app/api/core/frontend-dist/assets/es-edd3ba17.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/es-edd3ba17.svg rename to internal/app/api/core/frontend-dist/assets/es-edd3ba17.svg diff --git a/internal/ports/api/core/frontend-dist/assets/es-ga-0f1c2551.svg b/internal/app/api/core/frontend-dist/assets/es-ga-0f1c2551.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/es-ga-0f1c2551.svg rename to internal/app/api/core/frontend-dist/assets/es-ga-0f1c2551.svg diff --git a/internal/ports/api/core/frontend-dist/assets/es-ga-1955fb3b.svg b/internal/app/api/core/frontend-dist/assets/es-ga-1955fb3b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/es-ga-1955fb3b.svg rename to internal/app/api/core/frontend-dist/assets/es-ga-1955fb3b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/et-25b637b7.svg b/internal/app/api/core/frontend-dist/assets/et-25b637b7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/et-25b637b7.svg rename to internal/app/api/core/frontend-dist/assets/et-25b637b7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/et-b2239ad7.svg b/internal/app/api/core/frontend-dist/assets/et-b2239ad7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/et-b2239ad7.svg rename to internal/app/api/core/frontend-dist/assets/et-b2239ad7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/eu-605225b6.svg b/internal/app/api/core/frontend-dist/assets/eu-605225b6.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/eu-605225b6.svg rename to internal/app/api/core/frontend-dist/assets/eu-605225b6.svg diff --git a/internal/ports/api/core/frontend-dist/assets/eu-f8fd4ae7.svg b/internal/app/api/core/frontend-dist/assets/eu-f8fd4ae7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/eu-f8fd4ae7.svg rename to internal/app/api/core/frontend-dist/assets/eu-f8fd4ae7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fi-012edd98.svg b/internal/app/api/core/frontend-dist/assets/fi-012edd98.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fi-012edd98.svg rename to internal/app/api/core/frontend-dist/assets/fi-012edd98.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fi-f4064089.svg b/internal/app/api/core/frontend-dist/assets/fi-f4064089.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fi-f4064089.svg rename to internal/app/api/core/frontend-dist/assets/fi-f4064089.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fj-0243d39f.svg b/internal/app/api/core/frontend-dist/assets/fj-0243d39f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fj-0243d39f.svg rename to internal/app/api/core/frontend-dist/assets/fj-0243d39f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fj-f8b5b752.svg b/internal/app/api/core/frontend-dist/assets/fj-f8b5b752.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fj-f8b5b752.svg rename to internal/app/api/core/frontend-dist/assets/fj-f8b5b752.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fk-398be37e.svg b/internal/app/api/core/frontend-dist/assets/fk-398be37e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fk-398be37e.svg rename to internal/app/api/core/frontend-dist/assets/fk-398be37e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fk-4862e30d.svg b/internal/app/api/core/frontend-dist/assets/fk-4862e30d.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fk-4862e30d.svg rename to internal/app/api/core/frontend-dist/assets/fk-4862e30d.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fm-07fe66ad.svg b/internal/app/api/core/frontend-dist/assets/fm-07fe66ad.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fm-07fe66ad.svg rename to internal/app/api/core/frontend-dist/assets/fm-07fe66ad.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fm-f7906ddc.svg b/internal/app/api/core/frontend-dist/assets/fm-f7906ddc.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fm-f7906ddc.svg rename to internal/app/api/core/frontend-dist/assets/fm-f7906ddc.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fo-87270006.svg b/internal/app/api/core/frontend-dist/assets/fo-87270006.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fo-87270006.svg rename to internal/app/api/core/frontend-dist/assets/fo-87270006.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fo-9b46d4a8.svg b/internal/app/api/core/frontend-dist/assets/fo-9b46d4a8.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fo-9b46d4a8.svg rename to internal/app/api/core/frontend-dist/assets/fo-9b46d4a8.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fr-0d02622a.svg b/internal/app/api/core/frontend-dist/assets/fr-0d02622a.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fr-0d02622a.svg rename to internal/app/api/core/frontend-dist/assets/fr-0d02622a.svg diff --git a/internal/ports/api/core/frontend-dist/assets/fr-c19557a7.svg b/internal/app/api/core/frontend-dist/assets/fr-c19557a7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/fr-c19557a7.svg rename to internal/app/api/core/frontend-dist/assets/fr-c19557a7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ga-cb2951db.svg b/internal/app/api/core/frontend-dist/assets/ga-cb2951db.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ga-cb2951db.svg rename to internal/app/api/core/frontend-dist/assets/ga-cb2951db.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ga-f7b775c4.svg b/internal/app/api/core/frontend-dist/assets/ga-f7b775c4.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ga-f7b775c4.svg rename to internal/app/api/core/frontend-dist/assets/ga-f7b775c4.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gb-4b739ae8.svg b/internal/app/api/core/frontend-dist/assets/gb-4b739ae8.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gb-4b739ae8.svg rename to internal/app/api/core/frontend-dist/assets/gb-4b739ae8.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gb-51a8613a.svg b/internal/app/api/core/frontend-dist/assets/gb-51a8613a.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gb-51a8613a.svg rename to internal/app/api/core/frontend-dist/assets/gb-51a8613a.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gb-eng-2dd36838.svg b/internal/app/api/core/frontend-dist/assets/gb-eng-2dd36838.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gb-eng-2dd36838.svg rename to internal/app/api/core/frontend-dist/assets/gb-eng-2dd36838.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gb-eng-53797ba9.svg b/internal/app/api/core/frontend-dist/assets/gb-eng-53797ba9.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gb-eng-53797ba9.svg rename to internal/app/api/core/frontend-dist/assets/gb-eng-53797ba9.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gb-nir-14593385.svg b/internal/app/api/core/frontend-dist/assets/gb-nir-14593385.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gb-nir-14593385.svg rename to internal/app/api/core/frontend-dist/assets/gb-nir-14593385.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gb-nir-ae91c319.svg b/internal/app/api/core/frontend-dist/assets/gb-nir-ae91c319.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gb-nir-ae91c319.svg rename to internal/app/api/core/frontend-dist/assets/gb-nir-ae91c319.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gb-sct-19ed371e.svg b/internal/app/api/core/frontend-dist/assets/gb-sct-19ed371e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gb-sct-19ed371e.svg rename to internal/app/api/core/frontend-dist/assets/gb-sct-19ed371e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gb-sct-7b55bce7.svg b/internal/app/api/core/frontend-dist/assets/gb-sct-7b55bce7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gb-sct-7b55bce7.svg rename to internal/app/api/core/frontend-dist/assets/gb-sct-7b55bce7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gb-wls-3a95845d.svg b/internal/app/api/core/frontend-dist/assets/gb-wls-3a95845d.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gb-wls-3a95845d.svg rename to internal/app/api/core/frontend-dist/assets/gb-wls-3a95845d.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gb-wls-d3c5b996.svg b/internal/app/api/core/frontend-dist/assets/gb-wls-d3c5b996.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gb-wls-d3c5b996.svg rename to internal/app/api/core/frontend-dist/assets/gb-wls-d3c5b996.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gd-495e20bd.svg b/internal/app/api/core/frontend-dist/assets/gd-495e20bd.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gd-495e20bd.svg rename to internal/app/api/core/frontend-dist/assets/gd-495e20bd.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gd-b8fdff46.svg b/internal/app/api/core/frontend-dist/assets/gd-b8fdff46.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gd-b8fdff46.svg rename to internal/app/api/core/frontend-dist/assets/gd-b8fdff46.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ge-9f2584df.svg b/internal/app/api/core/frontend-dist/assets/ge-9f2584df.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ge-9f2584df.svg rename to internal/app/api/core/frontend-dist/assets/ge-9f2584df.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ge-e9d0f108.svg b/internal/app/api/core/frontend-dist/assets/ge-e9d0f108.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ge-e9d0f108.svg rename to internal/app/api/core/frontend-dist/assets/ge-e9d0f108.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gf-53afc127.svg b/internal/app/api/core/frontend-dist/assets/gf-53afc127.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gf-53afc127.svg rename to internal/app/api/core/frontend-dist/assets/gf-53afc127.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gf-56168b44.svg b/internal/app/api/core/frontend-dist/assets/gf-56168b44.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gf-56168b44.svg rename to internal/app/api/core/frontend-dist/assets/gf-56168b44.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gg-3457d341.svg b/internal/app/api/core/frontend-dist/assets/gg-3457d341.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gg-3457d341.svg rename to internal/app/api/core/frontend-dist/assets/gg-3457d341.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gg-f6ec0e51.svg b/internal/app/api/core/frontend-dist/assets/gg-f6ec0e51.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gg-f6ec0e51.svg rename to internal/app/api/core/frontend-dist/assets/gg-f6ec0e51.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gh-4afd4198.svg b/internal/app/api/core/frontend-dist/assets/gh-4afd4198.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gh-4afd4198.svg rename to internal/app/api/core/frontend-dist/assets/gh-4afd4198.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gh-86635202.svg b/internal/app/api/core/frontend-dist/assets/gh-86635202.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gh-86635202.svg rename to internal/app/api/core/frontend-dist/assets/gh-86635202.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gi-053a0a90.svg b/internal/app/api/core/frontend-dist/assets/gi-053a0a90.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gi-053a0a90.svg rename to internal/app/api/core/frontend-dist/assets/gi-053a0a90.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gi-05d68008.svg b/internal/app/api/core/frontend-dist/assets/gi-05d68008.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gi-05d68008.svg rename to internal/app/api/core/frontend-dist/assets/gi-05d68008.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gl-15a60b07.svg b/internal/app/api/core/frontend-dist/assets/gl-15a60b07.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gl-15a60b07.svg rename to internal/app/api/core/frontend-dist/assets/gl-15a60b07.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gl-debe7773.svg b/internal/app/api/core/frontend-dist/assets/gl-debe7773.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gl-debe7773.svg rename to internal/app/api/core/frontend-dist/assets/gl-debe7773.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gm-26a1fd6b.svg b/internal/app/api/core/frontend-dist/assets/gm-26a1fd6b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gm-26a1fd6b.svg rename to internal/app/api/core/frontend-dist/assets/gm-26a1fd6b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gm-726e760b.svg b/internal/app/api/core/frontend-dist/assets/gm-726e760b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gm-726e760b.svg rename to internal/app/api/core/frontend-dist/assets/gm-726e760b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gn-8d20e686.svg b/internal/app/api/core/frontend-dist/assets/gn-8d20e686.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gn-8d20e686.svg rename to internal/app/api/core/frontend-dist/assets/gn-8d20e686.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gn-ee01e7dd.svg b/internal/app/api/core/frontend-dist/assets/gn-ee01e7dd.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gn-ee01e7dd.svg rename to internal/app/api/core/frontend-dist/assets/gn-ee01e7dd.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gp-22ae75ed.svg b/internal/app/api/core/frontend-dist/assets/gp-22ae75ed.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gp-22ae75ed.svg rename to internal/app/api/core/frontend-dist/assets/gp-22ae75ed.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gp-5b6e2777.svg b/internal/app/api/core/frontend-dist/assets/gp-5b6e2777.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gp-5b6e2777.svg rename to internal/app/api/core/frontend-dist/assets/gp-5b6e2777.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gq-a3bf98e3.svg b/internal/app/api/core/frontend-dist/assets/gq-a3bf98e3.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gq-a3bf98e3.svg rename to internal/app/api/core/frontend-dist/assets/gq-a3bf98e3.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gq-be2561d6.svg b/internal/app/api/core/frontend-dist/assets/gq-be2561d6.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gq-be2561d6.svg rename to internal/app/api/core/frontend-dist/assets/gq-be2561d6.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gr-a184070f.svg b/internal/app/api/core/frontend-dist/assets/gr-a184070f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gr-a184070f.svg rename to internal/app/api/core/frontend-dist/assets/gr-a184070f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gr-a4519d98.svg b/internal/app/api/core/frontend-dist/assets/gr-a4519d98.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gr-a4519d98.svg rename to internal/app/api/core/frontend-dist/assets/gr-a4519d98.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gs-dcac009d.svg b/internal/app/api/core/frontend-dist/assets/gs-dcac009d.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gs-dcac009d.svg rename to internal/app/api/core/frontend-dist/assets/gs-dcac009d.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gs-fd6ad76e.svg b/internal/app/api/core/frontend-dist/assets/gs-fd6ad76e.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gs-fd6ad76e.svg rename to internal/app/api/core/frontend-dist/assets/gs-fd6ad76e.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gt-53d6bd19.svg b/internal/app/api/core/frontend-dist/assets/gt-53d6bd19.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gt-53d6bd19.svg rename to internal/app/api/core/frontend-dist/assets/gt-53d6bd19.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gt-cb60868c.svg b/internal/app/api/core/frontend-dist/assets/gt-cb60868c.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gt-cb60868c.svg rename to internal/app/api/core/frontend-dist/assets/gt-cb60868c.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gu-0fc8abf7.svg b/internal/app/api/core/frontend-dist/assets/gu-0fc8abf7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gu-0fc8abf7.svg rename to internal/app/api/core/frontend-dist/assets/gu-0fc8abf7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gu-865d2c85.svg b/internal/app/api/core/frontend-dist/assets/gu-865d2c85.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gu-865d2c85.svg rename to internal/app/api/core/frontend-dist/assets/gu-865d2c85.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gw-35d8c841.svg b/internal/app/api/core/frontend-dist/assets/gw-35d8c841.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gw-35d8c841.svg rename to internal/app/api/core/frontend-dist/assets/gw-35d8c841.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gw-9383444c.svg b/internal/app/api/core/frontend-dist/assets/gw-9383444c.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gw-9383444c.svg rename to internal/app/api/core/frontend-dist/assets/gw-9383444c.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gy-81301929.svg b/internal/app/api/core/frontend-dist/assets/gy-81301929.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gy-81301929.svg rename to internal/app/api/core/frontend-dist/assets/gy-81301929.svg diff --git a/internal/ports/api/core/frontend-dist/assets/gy-97253f86.svg b/internal/app/api/core/frontend-dist/assets/gy-97253f86.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/gy-97253f86.svg rename to internal/app/api/core/frontend-dist/assets/gy-97253f86.svg diff --git a/internal/ports/api/core/frontend-dist/assets/hk-3925e785.svg b/internal/app/api/core/frontend-dist/assets/hk-3925e785.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/hk-3925e785.svg rename to internal/app/api/core/frontend-dist/assets/hk-3925e785.svg diff --git a/internal/ports/api/core/frontend-dist/assets/hk-89b05a22.svg b/internal/app/api/core/frontend-dist/assets/hk-89b05a22.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/hk-89b05a22.svg rename to internal/app/api/core/frontend-dist/assets/hk-89b05a22.svg diff --git a/internal/ports/api/core/frontend-dist/assets/hm-3c45173f.svg b/internal/app/api/core/frontend-dist/assets/hm-3c45173f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/hm-3c45173f.svg rename to internal/app/api/core/frontend-dist/assets/hm-3c45173f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/hm-962e9410.svg b/internal/app/api/core/frontend-dist/assets/hm-962e9410.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/hm-962e9410.svg rename to internal/app/api/core/frontend-dist/assets/hm-962e9410.svg diff --git a/internal/ports/api/core/frontend-dist/assets/hn-2b4bafff.svg b/internal/app/api/core/frontend-dist/assets/hn-2b4bafff.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/hn-2b4bafff.svg rename to internal/app/api/core/frontend-dist/assets/hn-2b4bafff.svg diff --git a/internal/ports/api/core/frontend-dist/assets/hn-f7828d93.svg b/internal/app/api/core/frontend-dist/assets/hn-f7828d93.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/hn-f7828d93.svg rename to internal/app/api/core/frontend-dist/assets/hn-f7828d93.svg diff --git a/internal/ports/api/core/frontend-dist/assets/hr-a6187e3f.svg b/internal/app/api/core/frontend-dist/assets/hr-a6187e3f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/hr-a6187e3f.svg rename to internal/app/api/core/frontend-dist/assets/hr-a6187e3f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/hr-c853a9f1.svg b/internal/app/api/core/frontend-dist/assets/hr-c853a9f1.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/hr-c853a9f1.svg rename to internal/app/api/core/frontend-dist/assets/hr-c853a9f1.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ht-84187767.svg b/internal/app/api/core/frontend-dist/assets/ht-84187767.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ht-84187767.svg rename to internal/app/api/core/frontend-dist/assets/ht-84187767.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ht-9877b482.svg b/internal/app/api/core/frontend-dist/assets/ht-9877b482.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ht-9877b482.svg rename to internal/app/api/core/frontend-dist/assets/ht-9877b482.svg diff --git a/internal/ports/api/core/frontend-dist/assets/hu-9e6bc6d7.svg b/internal/app/api/core/frontend-dist/assets/hu-9e6bc6d7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/hu-9e6bc6d7.svg rename to internal/app/api/core/frontend-dist/assets/hu-9e6bc6d7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/hu-ffc4edd5.svg b/internal/app/api/core/frontend-dist/assets/hu-ffc4edd5.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/hu-ffc4edd5.svg rename to internal/app/api/core/frontend-dist/assets/hu-ffc4edd5.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ic-4e5a5e63.svg b/internal/app/api/core/frontend-dist/assets/ic-4e5a5e63.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ic-4e5a5e63.svg rename to internal/app/api/core/frontend-dist/assets/ic-4e5a5e63.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ic-9a584e04.svg b/internal/app/api/core/frontend-dist/assets/ic-9a584e04.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ic-9a584e04.svg rename to internal/app/api/core/frontend-dist/assets/ic-9a584e04.svg diff --git a/internal/ports/api/core/frontend-dist/assets/id-5cd3acc4.svg b/internal/app/api/core/frontend-dist/assets/id-5cd3acc4.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/id-5cd3acc4.svg rename to internal/app/api/core/frontend-dist/assets/id-5cd3acc4.svg diff --git a/internal/ports/api/core/frontend-dist/assets/id-b8cd30f2.svg b/internal/app/api/core/frontend-dist/assets/id-b8cd30f2.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/id-b8cd30f2.svg rename to internal/app/api/core/frontend-dist/assets/id-b8cd30f2.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ie-860168f5.svg b/internal/app/api/core/frontend-dist/assets/ie-860168f5.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ie-860168f5.svg rename to internal/app/api/core/frontend-dist/assets/ie-860168f5.svg diff --git a/internal/ports/api/core/frontend-dist/assets/ie-f82568d7.svg b/internal/app/api/core/frontend-dist/assets/ie-f82568d7.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/ie-f82568d7.svg rename to internal/app/api/core/frontend-dist/assets/ie-f82568d7.svg diff --git a/internal/ports/api/core/frontend-dist/assets/il-0004f90f.svg b/internal/app/api/core/frontend-dist/assets/il-0004f90f.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/il-0004f90f.svg rename to internal/app/api/core/frontend-dist/assets/il-0004f90f.svg diff --git a/internal/ports/api/core/frontend-dist/assets/il-a9c90b0c.svg b/internal/app/api/core/frontend-dist/assets/il-a9c90b0c.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/il-a9c90b0c.svg rename to internal/app/api/core/frontend-dist/assets/il-a9c90b0c.svg diff --git a/internal/ports/api/core/frontend-dist/assets/im-56a6eed5.svg b/internal/app/api/core/frontend-dist/assets/im-56a6eed5.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/im-56a6eed5.svg rename to internal/app/api/core/frontend-dist/assets/im-56a6eed5.svg diff --git a/internal/ports/api/core/frontend-dist/assets/im-bf7e365b.svg b/internal/app/api/core/frontend-dist/assets/im-bf7e365b.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/im-bf7e365b.svg rename to internal/app/api/core/frontend-dist/assets/im-bf7e365b.svg diff --git a/internal/ports/api/core/frontend-dist/assets/in-24cd1522.svg b/internal/app/api/core/frontend-dist/assets/in-24cd1522.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/in-24cd1522.svg rename to internal/app/api/core/frontend-dist/assets/in-24cd1522.svg diff --git a/internal/ports/api/core/frontend-dist/assets/in-9a372951.svg b/internal/app/api/core/frontend-dist/assets/in-9a372951.svg similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/in-9a372951.svg rename to internal/app/api/core/frontend-dist/assets/in-9a372951.svg diff --git a/internal/ports/api/core/frontend-dist/assets/index-0e8a2841.css b/internal/app/api/core/frontend-dist/assets/index-0e8a2841.css similarity index 100% rename from internal/ports/api/core/frontend-dist/assets/index-0e8a2841.css rename to internal/app/api/core/frontend-dist/assets/index-0e8a2841.css diff --git a/internal/ports/api/core/frontend-dist/assets/index-62a1c0a6.js b/internal/app/api/core/frontend-dist/assets/index-62a1c0a6.js similarity index 98% rename from internal/ports/api/core/frontend-dist/assets/index-62a1c0a6.js rename to internal/app/api/core/frontend-dist/assets/index-62a1c0a6.js index e1e5eda..d006562 100644 --- a/internal/ports/api/core/frontend-dist/assets/index-62a1c0a6.js +++ b/internal/app/api/core/frontend-dist/assets/index-62a1c0a6.js @@ -56,7 +56,7 @@ PersistentKeepalive = 16 * vue-i18n v9.1.10 * (c) 2022 kazuya kawaguchi * Released under the MIT License. - */const Bh="9.1.10";function Kh(){typeof __VUE_I18N_FULL_INSTALL__!="boolean"&&(I6().__VUE_I18N_FULL_INSTALL__=!0),typeof __VUE_I18N_LEGACY_API__!="boolean"&&(I6().__VUE_I18N_LEGACY_API__=!0),typeof __INTLIFY_PROD_DEVTOOLS__!="boolean"&&(I6().__INTLIFY_PROD_DEVTOOLS__=!1)}function m2(c,...e){return _5(c,null,void 0)}const z0="__INTLIFY_META__",Q0=g3("__transrateVNode"),J0=g3("__datetimeParts"),c7=g3("__numberParts");g3("__enableEmitter");g3("__disableEmitter");const _s=g3("__setPluralRules");g3("__intlifyMeta");const ys=g3("__injectWithOption");let ie=0;function oe(c){return(e,t,s,l)=>c(t,s,V3()||void 0,l)}function D7(c,e){const{messages:t,__i18n:s}=e,l=w1(t)?t:X1(s)?{}:{[c]:{}};if(X1(s)&&s.forEach(({locale:n,resource:r})=>{n?(l[n]=l[n]||{},r5(r,l[n])):r5(r,l)}),e.flatJson)for(const n in l)Vs(l,n)&&K0(l[n]);return l}const O8=c=>!M2(c)||X1(c);function r5(c,e){if(O8(c)||O8(e))throw m2(20);for(const t in c)Vs(c,t)&&(O8(c[t])||O8(e[t])?e[t]=c[t]:r5(c[t],e[t]))}const Zh=()=>{const c=V3();return c&&c.type[z0]?{[z0]:c.type[z0]}:null};function R7(c={}){const{__root:e}=c,t=e===void 0;let s=B1(c.inheritLocale)?c.inheritLocale:!0;const l=a2(e&&s?e.locale.value:u1(c.locale)?c.locale:"en-US"),n=a2(e&&s?e.fallbackLocale.value:u1(c.fallbackLocale)||X1(c.fallbackLocale)||w1(c.fallbackLocale)||c.fallbackLocale===!1?c.fallbackLocale:l.value),r=a2(D7(l.value,c)),a=a2(w1(c.datetimeFormats)?c.datetimeFormats:{[l.value]:{}}),i=a2(w1(c.numberFormats)?c.numberFormats:{[l.value]:{}});let o=e?e.missingWarn:B1(c.missingWarn)||Y4(c.missingWarn)?c.missingWarn:!0,u=e?e.fallbackWarn:B1(c.fallbackWarn)||Y4(c.fallbackWarn)?c.fallbackWarn:!0,C=e?e.fallbackRoot:B1(c.fallbackRoot)?c.fallbackRoot:!0,z=!!c.fallbackFormat,H=o2(c.missing)?c.missing:null,p=o2(c.missing)?oe(c.missing):null,E=o2(c.postTranslation)?c.postTranslation:null,A=B1(c.warnHtmlMessage)?c.warnHtmlMessage:!0,L=!!c.escapeParameter;const O=e?e.modifiers:w1(c.modifiers)?c.modifiers:{};let T=c.pluralRules||e&&e.pluralRules,_;function x(){return Ih({version:Bh,locale:l.value,fallbackLocale:n.value,messages:r.value,datetimeFormats:a.value,numberFormats:i.value,modifiers:O,pluralRules:T,missing:p===null?void 0:p,missingWarn:o,fallbackWarn:u,fallbackFormat:z,unresolving:!0,postTranslation:E===null?void 0:E,warnHtmlMessage:A,escapeParameter:L,__datetimeFormatters:w1(_)?_.__datetimeFormatters:void 0,__numberFormatters:w1(_)?_.__numberFormatters:void 0,__v_emitter:w1(_)?_.__v_emitter:void 0,__meta:{framework:"vue"}})}_=x(),b6(_,l.value,n.value);function K(){return[l.value,n.value,r.value,a.value,i.value]}const D=F1({get:()=>l.value,set:w=>{l.value=w,_.locale=l.value}}),F=F1({get:()=>n.value,set:w=>{n.value=w,_.fallbackLocale=n.value,b6(_,l.value,w)}}),X=F1(()=>r.value),B=F1(()=>a.value),f1=F1(()=>i.value);function c1(){return o2(E)?E:null}function V1(w){E=w,_.postTranslation=w}function m1(){return H}function M1(w){w!==null&&(p=oe(w)),H=w,_.missing=p}function z1(w,j,r1,a1,p1,y1){K();let P1;if(__INTLIFY_PROD_DEVTOOLS__)try{Qc(Zh()),P1=w(_)}finally{Qc(null)}else P1=w(_);if(e2(P1)&&P1===y5){const[O1,j1]=j();return e&&C?a1(e):p1(O1)}else{if(y1(P1))return P1;throw m2(14)}}function n1(...w){return z1(j=>se(j,...w),()=>Y0(...w),"translate",j=>j.t(...w),j=>j,j=>u1(j))}function v1(...w){const[j,r1,a1]=w;if(a1&&!M2(a1))throw m2(15);return n1(j,r1,s2({resolvedMessage:!0},a1||{}))}function T1(...w){return z1(j=>le(j,...w),()=>G0(...w),"datetime format",j=>j.d(...w),()=>Xc,j=>u1(j))}function I1(...w){return z1(j=>re(j,...w),()=>X0(...w),"number format",j=>j.n(...w),()=>Xc,j=>u1(j))}function A1(w){return w.map(j=>u1(j)?W1(q4,null,j,0):j)}const q={normalize:A1,interpolate:w=>w,type:"vnode"};function U(...w){return z1(j=>{let r1;const a1=j;try{a1.processor=q,r1=se(a1,...w)}finally{a1.processor=null}return r1},()=>Y0(...w),"translate",j=>j[Q0](...w),j=>[W1(q4,null,j,0)],j=>X1(j))}function S(...w){return z1(j=>re(j,...w),()=>X0(...w),"number format",j=>j[c7](...w),()=>[],j=>u1(j)||X1(j))}function Y(...w){return z1(j=>le(j,...w),()=>G0(...w),"datetime format",j=>j[J0](...w),()=>[],j=>u1(j)||X1(j))}function s1(w){T=w,_.pluralRules=T}function i1(w,j){const r1=u1(j)?j:l.value,a1=g(r1);return n5(a1,w)!==null}function _1(w){let j=null;const r1=n8(_,n.value,l.value);for(let a1=0;a1{s&&(l.value=w,_.locale=w,b6(_,l.value,n.value))}),d3(e.fallbackLocale,w=>{s&&(n.value=w,_.fallbackLocale=w,b6(_,l.value,n.value))})),{id:ie,locale:D,fallbackLocale:F,get inheritLocale(){return s},set inheritLocale(w){s=w,w&&e&&(l.value=e.locale.value,n.value=e.fallbackLocale.value,b6(_,l.value,n.value))},get availableLocales(){return Object.keys(r.value).sort()},messages:X,datetimeFormats:B,numberFormats:f1,get modifiers(){return O},get pluralRules(){return T||{}},get isGlobal(){return t},get missingWarn(){return o},set missingWarn(w){o=w,_.missingWarn=o},get fallbackWarn(){return u},set fallbackWarn(w){u=w,_.fallbackWarn=u},get fallbackRoot(){return C},set fallbackRoot(w){C=w},get fallbackFormat(){return z},set fallbackFormat(w){z=w,_.fallbackFormat=z},get warnHtmlMessage(){return A},set warnHtmlMessage(w){A=w,_.warnHtmlMessage=w},get escapeParameter(){return L},set escapeParameter(w){L=w,_.escapeParameter=w},t:n1,rt:v1,d:T1,n:I1,te:i1,tm:D1,getLocaleMessage:g,setLocaleMessage:h,mergeLocaleMessage:V,getDateTimeFormat:b,setDateTimeFormat:P,mergeDateTimeFormat:R,getNumberFormat:G,setNumberFormat:l1,mergeNumberFormat:e1,getPostTranslationHandler:c1,setPostTranslationHandler:V1,getMissingHandler:m1,setMissingHandler:M1,[Q0]:U,[c7]:S,[J0]:Y,[_s]:s1,[ys]:c.__injectWithOption}}function Yh(c){const e=u1(c.locale)?c.locale:"en-US",t=u1(c.fallbackLocale)||X1(c.fallbackLocale)||w1(c.fallbackLocale)||c.fallbackLocale===!1?c.fallbackLocale:e,s=o2(c.missing)?c.missing:void 0,l=B1(c.silentTranslationWarn)||Y4(c.silentTranslationWarn)?!c.silentTranslationWarn:!0,n=B1(c.silentFallbackWarn)||Y4(c.silentFallbackWarn)?!c.silentFallbackWarn:!0,r=B1(c.fallbackRoot)?c.fallbackRoot:!0,a=!!c.formatFallbackMessages,i=w1(c.modifiers)?c.modifiers:{},o=c.pluralizationRules,u=o2(c.postTranslation)?c.postTranslation:void 0,C=u1(c.warnHtmlInMessage)?c.warnHtmlInMessage!=="off":!0,z=!!c.escapeParameterHtml,H=B1(c.sync)?c.sync:!0;let p=c.messages;if(w1(c.sharedMessages)){const x=c.sharedMessages;p=Object.keys(x).reduce((D,F)=>{const X=D[F]||(D[F]={});return s2(X,x[F]),D},p||{})}const{__i18n:E,__root:A,__injectWithOption:L}=c,O=c.datetimeFormats,T=c.numberFormats,_=c.flatJson;return{locale:e,fallbackLocale:t,messages:p,flatJson:_,datetimeFormats:O,numberFormats:T,missing:s,missingWarn:l,fallbackWarn:n,fallbackRoot:r,fallbackFormat:a,modifiers:i,pluralRules:o,postTranslation:u,warnHtmlMessage:C,escapeParameter:z,inheritLocale:H,__i18n:E,__root:A,__injectWithOption:L}}function e7(c={}){const e=R7(Yh(c)),t={id:e.id,get locale(){return e.locale.value},set locale(s){e.locale.value=s},get fallbackLocale(){return e.fallbackLocale.value},set fallbackLocale(s){e.fallbackLocale.value=s},get messages(){return e.messages.value},get datetimeFormats(){return e.datetimeFormats.value},get numberFormats(){return e.numberFormats.value},get availableLocales(){return e.availableLocales},get formatter(){return{interpolate(){return[]}}},set formatter(s){},get missing(){return e.getMissingHandler()},set missing(s){e.setMissingHandler(s)},get silentTranslationWarn(){return B1(e.missingWarn)?!e.missingWarn:e.missingWarn},set silentTranslationWarn(s){e.missingWarn=B1(s)?!s:s},get silentFallbackWarn(){return B1(e.fallbackWarn)?!e.fallbackWarn:e.fallbackWarn},set silentFallbackWarn(s){e.fallbackWarn=B1(s)?!s:s},get modifiers(){return e.modifiers},get formatFallbackMessages(){return e.fallbackFormat},set formatFallbackMessages(s){e.fallbackFormat=s},get postTranslation(){return e.getPostTranslationHandler()},set postTranslation(s){e.setPostTranslationHandler(s)},get sync(){return e.inheritLocale},set sync(s){e.inheritLocale=s},get warnHtmlInMessage(){return e.warnHtmlMessage?"warn":"off"},set warnHtmlInMessage(s){e.warnHtmlMessage=s!=="off"},get escapeParameterHtml(){return e.escapeParameter},set escapeParameterHtml(s){e.escapeParameter=s},get preserveDirectiveContent(){return!0},set preserveDirectiveContent(s){},get pluralizationRules(){return e.pluralRules||{}},__composer:e,t(...s){const[l,n,r]=s,a={};let i=null,o=null;if(!u1(l))throw m2(15);const u=l;return u1(n)?a.locale=n:X1(n)?i=n:w1(n)&&(o=n),X1(r)?i=r:w1(r)&&(o=r),e.t(u,i||o||{},a)},rt(...s){return e.rt(...s)},tc(...s){const[l,n,r]=s,a={plural:1};let i=null,o=null;if(!u1(l))throw m2(15);const u=l;return u1(n)?a.locale=n:e2(n)?a.plural=n:X1(n)?i=n:w1(n)&&(o=n),u1(r)?a.locale=r:X1(r)?i=r:w1(r)&&(o=r),e.t(u,i||o||{},a)},te(s,l){return e.te(s,l)},tm(s){return e.tm(s)},getLocaleMessage(s){return e.getLocaleMessage(s)},setLocaleMessage(s,l){e.setLocaleMessage(s,l)},mergeLocaleMessage(s,l){e.mergeLocaleMessage(s,l)},d(...s){return e.d(...s)},getDateTimeFormat(s){return e.getDateTimeFormat(s)},setDateTimeFormat(s,l){e.setDateTimeFormat(s,l)},mergeDateTimeFormat(s,l){e.mergeDateTimeFormat(s,l)},n(...s){return e.n(...s)},getNumberFormat(s){return e.getNumberFormat(s)},setNumberFormat(s,l){e.setNumberFormat(s,l)},mergeNumberFormat(s,l){e.mergeNumberFormat(s,l)},getChoiceIndex(s,l){return-1},__onComponentInstanceCreated(s){const{componentInstanceCreatedListener:l}=c;l&&l(s,t)}};return t}const F7={tag:{type:[String,Object]},locale:{type:String},scope:{type:String,validator:c=>c==="parent"||c==="global",default:"parent"},i18n:{type:Object}},fe={name:"i18n-t",props:s2({keypath:{type:String,required:!0},plural:{type:[Number,String],validator:c=>e2(c)||!isNaN(c)}},F7),setup(c,e){const{slots:t,attrs:s}=e,l=c.i18n||r8({useScope:c.scope,__useComponent:!0}),n=Object.keys(t).filter(r=>r!=="_");return()=>{const r={};c.locale&&(r.locale=c.locale),c.plural!==void 0&&(r.plural=u1(c.plural)?+c.plural:c.plural);const a=Gh(e,n),i=l[Q0](c.keypath,a,r),o=s2({},s);return u1(c.tag)||M2(c.tag)?W3(c.tag,o,i):W3(Y1,o,i)}}};function Gh({slots:c},e){return e.length===1&&e[0]==="default"?c.default?c.default():[]:e.reduce((t,s)=>{const l=c[s];return l&&(t[s]=l()),t},{})}function Ss(c,e,t,s){const{slots:l,attrs:n}=e;return()=>{const r={part:!0};let a={};c.locale&&(r.locale=c.locale),u1(c.format)?r.key=c.format:M2(c.format)&&(u1(c.format.key)&&(r.key=c.format.key),a=Object.keys(c.format).reduce((C,z)=>t.includes(z)?s2({},C,{[z]:c.format[z]}):C,{}));const i=s(c.value,r,a);let o=[r.key];X1(i)?o=i.map((C,z)=>{const H=l[C.type];return H?H({[C.type]:C.value,index:z,parts:i}):[C.value]}):u1(i)&&(o=[i]);const u=s2({},n);return u1(c.tag)||M2(c.tag)?W3(c.tag,u,o):W3(Y1,u,o)}}const Xh=["localeMatcher","style","unit","unitDisplay","currency","currencyDisplay","useGrouping","numberingSystem","minimumIntegerDigits","minimumFractionDigits","maximumFractionDigits","minimumSignificantDigits","maximumSignificantDigits","notation","formatMatcher"],ue={name:"i18n-n",props:s2({value:{type:Number,required:!0},format:{type:[String,Object]}},F7),setup(c,e){const t=c.i18n||r8({useScope:"parent",__useComponent:!0});return Ss(c,e,Xh,(...s)=>t[c7](...s))}},Qh=["dateStyle","timeStyle","fractionalSecondDigits","calendar","dayPeriod","numberingSystem","localeMatcher","timeZone","hour12","hourCycle","formatMatcher","weekday","era","year","month","day","hour","minute","second","timeZoneName"],he={name:"i18n-d",props:s2({value:{type:[Number,Date],required:!0},format:{type:[String,Object]}},F7),setup(c,e){const t=c.i18n||r8({useScope:"parent",__useComponent:!0});return Ss(c,e,Qh,(...s)=>t[J0](...s))}};function Jh(c,e){const t=c;if(c.mode==="composition")return t.__getInstance(e)||c.global;{const s=t.__getInstance(e);return s!=null?s.__composer:c.global.__composer}}function cm(c){const e=(t,{instance:s,value:l,modifiers:n})=>{if(!s||!s.$)throw m2(22);const r=Jh(c,s.$),a=em(l);t.textContent=r.t(...tm(a))};return{beforeMount:e,beforeUpdate:e}}function em(c){if(u1(c))return{path:c};if(w1(c)){if(!("path"in c))throw m2(19,"path");return c}else throw m2(20)}function tm(c){const{path:e,locale:t,args:s,choice:l,plural:n}=c,r={},a=s||{};return u1(t)&&(r.locale=t),e2(l)&&(r.plural=l),e2(n)&&(r.plural=n),[e,a,r]}function sm(c,e,...t){const s=w1(t[0])?t[0]:{},l=!!s.useI18nComponentName;(B1(s.globalInstall)?s.globalInstall:!0)&&(c.component(l?"i18n":fe.name,fe),c.component(ue.name,ue),c.component(he.name,he)),c.directive("t",cm(e))}function lm(c,e,t){return{beforeCreate(){const s=V3();if(!s)throw m2(22);const l=this.$options;if(l.i18n){const n=l.i18n;l.__i18n&&(n.__i18n=l.__i18n),n.__root=e,this===this.$root?this.$i18n=me(c,n):(n.__injectWithOption=!0,this.$i18n=e7(n))}else l.__i18n?this===this.$root?this.$i18n=me(c,l):this.$i18n=e7({__i18n:l.__i18n,__injectWithOption:!0,__root:e}):this.$i18n=c;c.__onComponentInstanceCreated(this.$i18n),t.__setInstance(s,this.$i18n),this.$t=(...n)=>this.$i18n.t(...n),this.$rt=(...n)=>this.$i18n.rt(...n),this.$tc=(...n)=>this.$i18n.tc(...n),this.$te=(n,r)=>this.$i18n.te(n,r),this.$d=(...n)=>this.$i18n.d(...n),this.$n=(...n)=>this.$i18n.n(...n),this.$tm=n=>this.$i18n.tm(n)},mounted(){},beforeUnmount(){const s=V3();if(!s)throw m2(22);delete this.$t,delete this.$rt,delete this.$tc,delete this.$te,delete this.$d,delete this.$n,delete this.$tm,t.__deleteInstance(s),delete this.$i18n}}}function me(c,e){c.locale=e.locale||c.locale,c.fallbackLocale=e.fallbackLocale||c.fallbackLocale,c.missing=e.missing||c.missing,c.silentTranslationWarn=e.silentTranslationWarn||c.silentFallbackWarn,c.silentFallbackWarn=e.silentFallbackWarn||c.silentFallbackWarn,c.formatFallbackMessages=e.formatFallbackMessages||c.formatFallbackMessages,c.postTranslation=e.postTranslation||c.postTranslation,c.warnHtmlInMessage=e.warnHtmlInMessage||c.warnHtmlInMessage,c.escapeParameterHtml=e.escapeParameterHtml||c.escapeParameterHtml,c.sync=e.sync||c.sync,c.__composer[_s](e.pluralizationRules||c.pluralizationRules);const t=D7(c.locale,{messages:e.messages,__i18n:e.__i18n});return Object.keys(t).forEach(s=>c.mergeLocaleMessage(s,t[s])),e.datetimeFormats&&Object.keys(e.datetimeFormats).forEach(s=>c.mergeDateTimeFormat(s,e.datetimeFormats[s])),e.numberFormats&&Object.keys(e.numberFormats).forEach(s=>c.mergeNumberFormat(s,e.numberFormats[s])),c}function nm(c={}){const e=__VUE_I18N_LEGACY_API__&&B1(c.legacy)?c.legacy:__VUE_I18N_LEGACY_API__,t=!!c.globalInjection,s=new Map,l=__VUE_I18N_LEGACY_API__&&e?e7(c):R7(c),n=g3(""),r={get mode(){return __VUE_I18N_LEGACY_API__&&e?"legacy":"composition"},async install(a,...i){a.__VUE_I18N_SYMBOL__=n,a.provide(a.__VUE_I18N_SYMBOL__,r),!e&&t&&fm(a,r.global),__VUE_I18N_FULL_INSTALL__&&sm(a,r,...i),__VUE_I18N_LEGACY_API__&&e&&a.mixin(lm(l,l.__composer,r))},get global(){return l},__instances:s,__getInstance(a){return s.get(a)||null},__setInstance(a,i){s.set(a,i)},__deleteInstance(a){s.delete(a)}};return r}function r8(c={}){const e=V3();if(e==null)throw m2(16);if(!e.appContext.app.__VUE_I18N_SYMBOL__)throw m2(17);const t=q2(e.appContext.app.__VUE_I18N_SYMBOL__);if(!t)throw m2(22);const s=t.mode==="composition"?t.global:t.global.__composer,l=b5(c)?"__i18n"in e.type?"local":"global":c.useScope?c.useScope:"local";if(l==="global"){let a=M2(c.messages)?c.messages:{};"__i18nGlobal"in e.type&&(a=D7(s.locale.value,{messages:a,__i18n:e.type.__i18nGlobal}));const i=Object.keys(a);if(i.length&&i.forEach(o=>{s.mergeLocaleMessage(o,a[o])}),M2(c.datetimeFormats)){const o=Object.keys(c.datetimeFormats);o.length&&o.forEach(u=>{s.mergeDateTimeFormat(u,c.datetimeFormats[u])})}if(M2(c.numberFormats)){const o=Object.keys(c.numberFormats);o.length&&o.forEach(u=>{s.mergeNumberFormat(u,c.numberFormats[u])})}return s}if(l==="parent"){let a=rm(t,e,c.__useComponent);return a==null&&(a=s),a}if(t.mode==="legacy")throw m2(18);const n=t;let r=n.__getInstance(e);if(r==null){const a=e.type,i=s2({},c);a.__i18n&&(i.__i18n=a.__i18n),s&&(i.__root=s),r=R7(i),am(n,e),n.__setInstance(e,r)}return r}function rm(c,e,t=!1){let s=null;const l=e.root;let n=e.parent;for(;n!=null;){const r=c;if(c.mode==="composition")s=r.__getInstance(n);else{const a=r.__getInstance(n);a!=null&&(s=a.__composer),t&&s&&!s[ys]&&(s=null)}if(s!=null||l===n)break;n=n.parent}return s}function am(c,e,t){s8(()=>{},e),_7(()=>{c.__deleteInstance(e)},e)}const im=["locale","fallbackLocale","availableLocales"],om=["t","rt","d","n","tm"];function fm(c,e){const t=Object.create(null);im.forEach(s=>{const l=Object.getOwnPropertyDescriptor(e,s);if(!l)throw m2(22);const n=G1(l.value)?{get(){return l.value.value},set(r){l.value.value=r}}:{get(){return l.get&&l.get()}};Object.defineProperty(t,s,n)}),c.config.globalProperties.$i18n=t,om.forEach(s=>{const l=Object.getOwnPropertyDescriptor(e,s);if(!l||!l.value)throw m2(22);Object.defineProperty(c.config.globalProperties,`$${s}`,l)})}Oh(Rh);Kh();if(__INTLIFY_PROD_DEVTOOLS__){const c=I6();c.__INTLIFY__=!0,wh(c.__INTLIFY_DEVTOOLS_GLOBAL_HOOK__)}const um=f("legend",{class:"mt-4"},"General",-1),hm={class:"form-group"},mm={class:"form-label mt-4"},dm={class:"form-group"},zm={class:"form-label mt-4"},Cm=f("legend",{class:"mt-4"},"Cryptography",-1),vm={key:0,class:"form-group"},Hm={class:"form-label mt-4"},Vm={class:"form-group"},Mm={class:"form-label mt-4"},pm={class:"form-group"},Lm={class:"form-label mt-4"},gm=f("legend",{class:"mt-4"},"Networking",-1),bm={key:0,class:"form-group"},_m={class:"form-label mt-4"},ym={class:"form-group"},Sm={class:"form-label mt-4"},wm={class:"form-group"},Em={class:"form-label mt-4"},km={class:"form-group"},Am={class:"form-label mt-4"},Pm={class:"form-group"},Tm={class:"form-label mt-4"},Om={class:"row"},xm={class:"form-group col-md-6"},Im={class:"form-label mt-4"},$m={class:"form-group col-md-6"},Nm={class:"form-label mt-4"},Dm=f("legend",{class:"mt-4"},"State",-1),Rm={class:"form-check form-switch"},Fm=f("label",{class:"form-check-label"},"Disabled",-1),jm={class:"form-check form-switch"},Um=f("label",{class:"form-check-label"},"Ignore global settings",-1),qm=f("div",{class:"flex-fill text-start"},[f("button",{type:"button",class:"btn btn-danger me-1"},"Delete")],-1),Wm=f("button",{type:"button",class:"btn btn-primary me-1"},"Save",-1),Bm=["onClick"],Km={__name:"PeerEditModal",props:{peerId:String,visible:Boolean},emits:["close"],setup(c,{emit:e}){const t=c,{t:s}=r8(),l=x7(),n=l8(),r=F1(()=>l.Find(t.peerId)),a=F1(()=>{let H=n.GetSelected;return H||(H={Identifier:"none",Mode:"server"}),H}),i=F1(()=>t.visible?a.value.Mode==="server"?r.value?s("interfaces.peer.edit")+": "+r.value.Name:s("interfaces.peer.new"):r.value?s("interfaces.endpoint.edit")+": "+r.value.Name:s("interfaces.endpoint.new"):""),o=a2(u());a2({title:"",content:"",cause:"",type:"normal"});function u(){return{Disabled:!1,IgnoreGlobalSettings:!0,Endpoint:{Value:"",Overridable:!1},AllowedIPsStr:{Value:"",Overridable:!1},ExtraAllowedIPsStr:"",PrivateKey:"",PublicKey:"",PresharedKey:"",PersistentKeepalive:{Value:0,Overridable:!1},DisplayName:"",Identifier:"",UserIdentifier:"",InterfaceConfig:{PublicKey:{Value:"",Overridable:!1},AddressStr:{Value:"",Overridable:!1},DnsStr:{Value:"",Overridable:!1},DnsSearchStr:{Value:"",Overridable:!1},Mtu:{Value:0,Overridable:!1},FirewallMark:{Value:0,Overridable:!1},RoutingTable:{Value:"",Overridable:!1},PreUp:{Value:"",Overridable:!1},PostUp:{Value:"",Overridable:!1},PreDown:{Value:"",Overridable:!1},PostDown:{Value:"",Overridable:!1}}}}d3(()=>t.visible,async(H,p)=>{p===!1&&H===!0&&(r.value||await C())});async function C(){console.log("loading new peer data..."),t2({title:"Authorization",text:"You have been logged in!"}),t2({title:"Authorization2",text:"You have been logged in!"}),t2({title:"Authorization3",text:"You have been logged in!"})}function z(){o.value=u(),e("close")}return(H,p)=>(C1(),L3(O7,{title:Z(i),visible:c.visible,onClose:z},{default:V2(()=>[f("fieldset",null,[um,f("div",hm,[f("label",mm,$(H.$t("modals.peeredit.displayname")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"A descriptive name of the peer","onUpdate:modelValue":p[0]||(p[0]=E=>o.value.DisplayName=E)},null,512),[[S1,o.value.DisplayName]])]),f("div",dm,[f("label",zm,$(H.$t("modals.peeredit.linkeduser")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Linked user","onUpdate:modelValue":p[1]||(p[1]=E=>o.value.UserIdentifier=E)},null,512),[[S1,o.value.UserIdentifier]])])]),f("fieldset",null,[Cm,Z(a).Mode==="server"?(C1(),b1("div",vm,[f("label",Hm,$(H.$t("modals.peeredit.privatekey")),1),g1(f("input",{type:"email",class:"form-control",placeholder:"The private key",required:"","onUpdate:modelValue":p[2]||(p[2]=E=>o.value.PrivateKey=E)},null,512),[[S1,o.value.PrivateKey]])])):R1("",!0),f("div",Vm,[f("label",Mm,$(H.$t("modals.peeredit.publickey")),1),g1(f("input",{type:"email",class:"form-control",placeholder:"The public key",required:"","onUpdate:modelValue":p[3]||(p[3]=E=>o.value.PublicKey=E)},null,512),[[S1,o.value.PublicKey]])]),f("div",pm,[f("label",Lm,$(H.$t("modals.peeredit.presharedkey")),1),g1(f("input",{type:"email",class:"form-control",placeholder:"Optional pre-shared key","onUpdate:modelValue":p[4]||(p[4]=E=>o.value.PresharedKey=E)},null,512),[[S1,o.value.PresharedKey]])])]),f("fieldset",null,[gm,Z(a).Mode==="client"?(C1(),b1("div",bm,[f("label",_m,$(H.$t("modals.peeredit.endpoint")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Endpoint Address","onUpdate:modelValue":p[5]||(p[5]=E=>o.value.Endpoint.Value=E)},null,512),[[S1,o.value.Endpoint.Value]])])):R1("",!0),f("div",ym,[f("label",Sm,$(H.$t("modals.peeredit.ips")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Client IP Address","onUpdate:modelValue":p[6]||(p[6]=E=>o.value.InterfaceConfig.AddressStr.Value=E)},null,512),[[S1,o.value.InterfaceConfig.AddressStr.Value]])]),f("div",wm,[f("label",Em,$(H.$t("modals.peeredit.allowedips")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Allowed IP Address","onUpdate:modelValue":p[7]||(p[7]=E=>o.value.AllowedIPsStr.Value=E)},null,512),[[S1,o.value.AllowedIPsStr.Value]])]),f("div",km,[f("label",Am,$(H.$t("modals.peeredit.extraallowedips")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Extra Allowed IP's (Server Sided)","onUpdate:modelValue":p[8]||(p[8]=E=>o.value.ExtraAllowedIPsStr.Value=E)},null,512),[[S1,o.value.ExtraAllowedIPsStr.Value]])]),f("div",Pm,[f("label",Tm,$(H.$t("modals.peeredit.dns")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Client DNS Servers","onUpdate:modelValue":p[9]||(p[9]=E=>o.value.InterfaceConfig.DnsStr.Value=E)},null,512),[[S1,o.value.InterfaceConfig.DnsStr.Value]])]),f("div",Om,[f("div",xm,[f("label",Im,$(H.$t("modals.peeredit.persistendkeepalive")),1),g1(f("input",{type:"number",class:"form-control",placeholder:"Persistent Keepalive (0 = off)","onUpdate:modelValue":p[10]||(p[10]=E=>o.value.PersistentKeepalive.Value=E)},null,512),[[S1,o.value.PersistentKeepalive.Value]])]),f("div",$m,[f("label",Nm,$(H.$t("modals.peeredit.mtu")),1),g1(f("input",{type:"number",class:"form-control",placeholder:"Client MTU (0 = default)","onUpdate:modelValue":p[11]||(p[11]=E=>o.value.InterfaceConfig.Mtu.Value=E)},null,512),[[S1,o.value.InterfaceConfig.Mtu.Value]])])])]),f("fieldset",null,[Dm,f("div",Rm,[g1(f("input",{class:"form-check-input",type:"checkbox","onUpdate:modelValue":p[12]||(p[12]=E=>o.value.Disabled=E)},null,512),[[t5,o.value.Disabled]]),Fm]),f("div",jm,[g1(f("input",{class:"form-check-input",type:"checkbox",checked:"","onUpdate:modelValue":p[13]||(p[13]=E=>o.value.IgnoreGlobalSettings=E)},null,512),[[t5,o.value.IgnoreGlobalSettings]]),Um])])]),footer:V2(()=>[qm,Wm,f("button",{onClick:i2(z,["prevent"]),type:"button",class:"btn btn-secondary"},"Discard",8,Bm)]),_:1},8,["title","visible"]))}};const Zm={class:"nav nav-tabs"},Ym=f("li",{class:"nav-item"},[f("a",{class:"nav-link active","data-bs-toggle":"tab",href:"#interface"},"Interface")],-1),Gm={key:0,class:"nav-item"},Xm=f("a",{class:"nav-link","data-bs-toggle":"tab",href:"#peerdefaults"},"Peer Defaults",-1),Qm=[Xm],Jm={id:"interfaceTabs",class:"tab-content"},cd={id:"interface",class:"tab-pane fade active show"},ed=f("legend",{class:"mt-4"},"General",-1),td={key:0,class:"form-group"},sd={class:"form-label mt-4"},ld={class:"form-group"},nd={class:"form-label mt-4"},rd=f("option",{value:"server"},"Server Mode",-1),ad=f("option",{value:"client"},"Client Mode",-1),id=f("option",{value:"any"},"Custom Mode",-1),od=[rd,ad,id],fd={class:"form-group"},ud={class:"form-label mt-4"},hd=f("legend",{class:"mt-4"},"Cryptography",-1),md={class:"form-group"},dd={class:"form-label mt-4"},zd={class:"form-group"},Cd={class:"form-label mt-4"},vd=f("legend",{class:"mt-4"},"Networking",-1),Hd={class:"form-group"},Vd={class:"form-label mt-4"},Md={key:0,class:"form-group"},pd={class:"form-label mt-4"},Ld={class:"form-group"},gd={class:"form-label mt-4"},bd={class:"form-group"},_d={class:"form-label mt-4"},yd={class:"row"},Sd={class:"form-group col-md-6"},wd={class:"form-label mt-4"},Ed={class:"form-group col-md-6"},kd={class:"form-label mt-4"},Ad={class:"row"},Pd={class:"form-group col-md-6"},Td={class:"form-label mt-4"},Od=f("div",{class:"form-group col-md-6"},null,-1),xd=f("legend",{class:"mt-4"},"Hooks",-1),Id={class:"form-group"},$d={class:"form-label mt-4"},Nd={class:"form-group"},Dd={class:"form-label mt-4"},Rd={class:"form-group"},Fd={class:"form-label mt-4"},jd={class:"form-group"},Ud={class:"form-label mt-4"},qd=f("legend",{class:"mt-4"},"State",-1),Wd={class:"form-check form-switch"},Bd=f("label",{class:"form-check-label"},"Disabled",-1),Kd={class:"form-check form-switch"},Zd=f("label",{class:"form-check-label"},"Save Config to File",-1),Yd={id:"peerdefaults",class:"tab-pane fade"},Gd=f("legend",{class:"mt-4"},"Networking",-1),Xd={class:"form-group"},Qd={class:"form-label mt-4"},Jd=f("small",{class:"form-text text-muted"},"Peers will get IP addresses from those subnets.",-1),cz={class:"form-group"},ez={class:"form-label mt-4"},tz=f("small",{class:"form-text text-muted"},"Peers will get IP addresses from those subnets.",-1),sz={class:"form-group"},lz={class:"form-label mt-4"},nz={class:"form-group"},rz={class:"form-label mt-4"},az={class:"form-group"},iz={class:"form-label mt-4"},oz={class:"row"},fz={class:"form-group col-md-6"},uz={class:"form-label mt-4"},hz={class:"form-group col-md-6"},mz={class:"form-label mt-4"},dz={class:"row"},zz={class:"form-group col-md-6"},Cz={class:"form-label mt-4"},vz={class:"form-group col-md-6"},Hz={class:"form-label mt-4"},Vz=f("legend",{class:"mt-4"},"Hooks",-1),Mz={class:"form-group"},pz={class:"form-label mt-4"},Lz={class:"form-group"},gz={class:"form-label mt-4"},bz={class:"form-group"},_z={class:"form-label mt-4"},yz={class:"form-group"},Sz={class:"form-label mt-4"},wz={class:"flex-fill text-start"},Ez=["onClick"],kz=["onClick"],Az=["onClick"],Pz={__name:"InterfaceEditModal",props:{interfaceId:String,visible:Boolean},emits:["close"],setup(c,{emit:e}){const t=c,{t:s}=r8(),l=l8(),n=F1(()=>l.Find(t.interfaceId)),r=F1(()=>t.visible?n.value?s("interfaces.interface.edit")+": "+n.value.Identifier:s("interfaces.interface.new"):""),a=a2(i());function i(){return{Disabled:!1,DisplayName:"",Identifier:"",Mode:"server",PublicKey:"",PrivateKey:"",ListenPort:51820,AddressStr:"",DnsStr:"",DnsSearchStr:"",Mtu:0,FirewallMark:0,RoutingTable:"",PreUp:"",PostUp:"",PreDown:"",PostDown:"",SaveConfig:!1,PeerDefNetworkStr:"",PeerDefDnsStr:"",PeerDefDnsSearchStr:"",PeerDefEndpoint:"",PeerDefAllowedIPsStr:"",PeerDefMtu:0,PeerDefPersistentKeepalive:0,PeerDefFirewallMark:0,PeerDefRoutingTable:"",PeerDefPreUp:"",PeerDefPostUp:"",PeerDefPreDown:"",PeerDefPostDown:""}}d3(()=>t.visible,async(z,H)=>{H===!1&&z===!0&&(console.log(n.value),n.value?(a.value.Disabled=n.value.Disabled,a.value.Identifier=n.value.Identifier,a.value.DisplayName=n.value.DisplayName,a.value.Mode=n.value.Mode,a.value.PublicKey=n.value.PublicKey,a.value.PrivateKey=n.value.PrivateKey,a.value.ListenPort=n.value.ListenPort,a.value.AddressStr=n.value.AddressStr,a.value.DnsStr=n.value.DnsStr,a.value.DnsSearchStr=n.value.DnsSearchStr,a.value.Mtu=n.value.Mtu,a.value.FirewallMark=n.value.FirewallMark,a.value.RoutingTable=n.value.RoutingTable,a.value.PreUp=n.value.PreUp,a.value.PostUp=n.value.PostUp,a.value.PreDown=n.value.PreDown,a.value.PostDown=n.value.PostDown,a.value.SaveConfig=n.value.SaveConfig,a.value.PeerDefNetworkStr=n.value.PeerDefNetworkStr,a.value.PeerDefDnsStr=n.value.PeerDefDnsStr,a.value.PeerDefDnsSearchStr=n.value.PeerDefDnsSearchStr,a.value.PeerDefEndpoint=n.value.PeerDefEndpoint,a.value.PeerDefAllowedIPsStr=n.value.PeerDefAllowedIPsStr,a.value.PeerDefMtu=n.value.PeerDefMtu,a.value.PeerDefPersistentKeepalive=n.value.PeerDefPersistentKeepalive,a.value.PeerDefFirewallMark=n.value.PeerDefFirewallMark,a.value.PeerDefRoutingTable=n.value.PeerDefRoutingTable,a.value.PeerDefPreUp=n.value.PeerDefPreUp,a.value.PeerDefPostUp=n.value.PeerDefPostUp,a.value.PeerDefPreDown=n.value.PeerDefPreDown,a.value.PeerDefPostDown=n.value.PeerDefPostDown):(await l.PrepareInterface(),a.value.Identifier=l.Prepared.Identifier,a.value.DisplayName=l.Prepared.DisplayName,a.value.Mode=l.Prepared.Mode,a.value.PublicKey=l.Prepared.PublicKey,a.value.PrivateKey=l.Prepared.PrivateKey,a.value.ListenPort=l.Prepared.ListenPort,a.value.AddressStr=l.Prepared.AddressStr,a.value.DnsStr=l.Prepared.DnsStr,a.value.DnsSearchStr=l.Prepared.DnsSearchStr,a.value.Mtu=l.Prepared.Mtu,a.value.FirewallMark=l.Prepared.FirewallMark,a.value.RoutingTable=l.Prepared.RoutingTable,a.value.PreUp=l.Prepared.PreUp,a.value.PostUp=l.Prepared.PostUp,a.value.PreDown=l.Prepared.PreDown,a.value.PostDown=l.Prepared.PostDown,a.value.SaveConfig=l.Prepared.SaveConfig,a.value.PeerDefNetworkStr=l.Prepared.PeerDefNetworkStr,a.value.PeerDefDnsStr=l.Prepared.PeerDefDnsStr,a.value.PeerDefDnsSearchStr=l.Prepared.PeerDefDnsSearchStr,a.value.PeerDefEndpoint=l.Prepared.PeerDefEndpoint,a.value.PeerDefAllowedIPsStr=l.Prepared.PeerDefAllowedIPsStr,a.value.PeerDefMtu=n.value.PeerDefMtu,a.value.PeerDefPersistentKeepalive=l.Prepared.PeerDefPersistentKeepalive,a.value.PeerDefFirewallMark=l.Prepared.PeerDefFirewallMark,a.value.PeerDefRoutingTable=l.Prepared.PeerDefRoutingTable,a.value.PeerDefPreUp=l.Prepared.PeerDefPreUp,a.value.PeerDefPostUp=l.Prepared.PeerDefPostUp,a.value.PeerDefPreDown=l.Prepared.PeerDefPreDown,a.value.PeerDefPostDown=l.Prepared.PeerDefPostDown))});function o(){a.value=i(),e("close")}async function u(){try{t.interfaceId!=="#NEW#"?await l.UpdateInterface(n.value.Identifier,a.value):await l.CreateInterface(a.value),o()}catch{t2({title:"Backend Connection Failure",text:"Failed to save interface!",type:"error"})}}async function C(){try{await l.DeleteInterface(n.value.Identifier),o()}catch{t2({title:"Backend Connection Failure",text:"Failed to delete interface!",type:"error"})}}return(z,H)=>(C1(),L3(O7,{title:Z(r),visible:c.visible,onClose:o},{default:V2(()=>[f("ul",Zm,[Ym,a.value.Mode==="server"?(C1(),b1("li",Gm,Qm)):R1("",!0)]),f("div",Jm,[f("div",cd,[f("fieldset",null,[ed,t.interfaceId==="#NEW#"?(C1(),b1("div",td,[f("label",sd,$(z.$t("modals.interfaceedit.identifier")),1),g1(f("input",{"onUpdate:modelValue":H[0]||(H[0]=p=>a.value.Identifier=p),class:"form-control",placeholder:"The device identifier",type:"text"},null,512),[[S1,a.value.Identifier]])])):R1("",!0),f("div",ld,[f("label",nd,$(z.$t("modals.interfaceedit.displayname")),1),g1(f("select",{"onUpdate:modelValue":H[1]||(H[1]=p=>a.value.Mode=p),class:"form-select"},od,512),[[F0,a.value.Mode]])]),f("div",fd,[f("label",ud,$(z.$t("modals.interfaceedit.displayname")),1),g1(f("input",{"onUpdate:modelValue":H[2]||(H[2]=p=>a.value.DisplayName=p),class:"form-control",placeholder:"A descriptive name of the interface",type:"text"},null,512),[[S1,a.value.DisplayName]])])]),f("fieldset",null,[hd,f("div",md,[f("label",dd,$(z.$t("modals.interfaceedit.privatekey")),1),g1(f("input",{"onUpdate:modelValue":H[3]||(H[3]=p=>a.value.PrivateKey=p),class:"form-control",placeholder:"The private key",required:"",type:"email"},null,512),[[S1,a.value.PrivateKey]])]),f("div",zd,[f("label",Cd,$(z.$t("modals.interfaceedit.publickey")),1),g1(f("input",{"onUpdate:modelValue":H[4]||(H[4]=p=>a.value.PublicKey=p),class:"form-control",placeholder:"The public key",required:"",type:"email"},null,512),[[S1,a.value.PublicKey]])])]),f("fieldset",null,[vd,f("div",Hd,[f("label",Vd,$(z.$t("modals.interfaceedit.ips")),1),g1(f("input",{"onUpdate:modelValue":H[5]||(H[5]=p=>a.value.AddressStr=p),class:"form-control",placeholder:"IP Address",type:"text"},null,512),[[S1,a.value.AddressStr]])]),a.value.Type==="server"?(C1(),b1("div",Md,[f("label",pd,$(z.$t("modals.interfaceedit.listenport")),1),g1(f("input",{"onUpdate:modelValue":H[6]||(H[6]=p=>a.value.ListenPort=p),class:"form-control",placeholder:"Listen Port",type:"text"},null,512),[[S1,a.value.ListenPort]])])):R1("",!0),f("div",Ld,[f("label",gd,$(z.$t("modals.interfaceedit.dns")),1),g1(f("input",{"onUpdate:modelValue":H[7]||(H[7]=p=>a.value.DnsStr=p),class:"form-control",placeholder:"DNS Servers",type:"text"},null,512),[[S1,a.value.DnsStr]])]),f("div",bd,[f("label",_d,$(z.$t("modals.interfaceedit.dnssearch")),1),g1(f("input",{"onUpdate:modelValue":H[8]||(H[8]=p=>a.value.DnsSearchStr=p),class:"form-control",placeholder:"DNS Search prefix",type:"text"},null,512),[[S1,a.value.DnsSearchStr]])]),f("div",yd,[f("div",Sd,[f("label",wd,$(z.$t("modals.interfaceedit.mtu")),1),g1(f("input",{"onUpdate:modelValue":H[9]||(H[9]=p=>a.value.Mtu=p),class:"form-control",placeholder:"Client MTU (0 = default)",type:"number"},null,512),[[S1,a.value.Mtu]])]),f("div",Ed,[f("label",kd,$(z.$t("modals.interfaceedit.firewallmark")),1),g1(f("input",{"onUpdate:modelValue":H[10]||(H[10]=p=>a.value.FirewallMark=p),class:"form-control",placeholder:"Firewall Mark (0 = default)",type:"number"},null,512),[[S1,a.value.FirewallMark]])])]),f("div",Ad,[f("div",Pd,[f("label",Td,$(z.$t("modals.interfaceedit.routingtable")),1),g1(f("input",{"onUpdate:modelValue":H[11]||(H[11]=p=>a.value.RoutingTable=p),class:"form-control",placeholder:"Routing Table (0 = default)",type:"number"},null,512),[[S1,a.value.RoutingTable]])]),Od])]),f("fieldset",null,[xd,f("div",Id,[f("label",$d,$(z.$t("modals.interfaceedit.preup")),1),g1(f("textarea",{"onUpdate:modelValue":H[12]||(H[12]=p=>a.value.PreUp=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PreUp]])]),f("div",Nd,[f("label",Dd,$(z.$t("modals.interfaceedit.postup")),1),g1(f("textarea",{"onUpdate:modelValue":H[13]||(H[13]=p=>a.value.PostUp=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PostUp]])]),f("div",Rd,[f("label",Fd,$(z.$t("modals.interfaceedit.predown")),1),g1(f("textarea",{"onUpdate:modelValue":H[14]||(H[14]=p=>a.value.PreDown=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PreDown]])]),f("div",jd,[f("label",Ud,$(z.$t("modals.interfaceedit.postdown")),1),g1(f("textarea",{"onUpdate:modelValue":H[15]||(H[15]=p=>a.value.PostDown=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PostDown]])])]),f("fieldset",null,[qd,f("div",Wd,[g1(f("input",{"onUpdate:modelValue":H[16]||(H[16]=p=>a.value.Disabled=p),class:"form-check-input",type:"checkbox"},null,512),[[t5,a.value.Disabled]]),Bd]),f("div",Kd,[g1(f("input",{"onUpdate:modelValue":H[17]||(H[17]=p=>a.value.SaveConfig=p),checked:"",class:"form-check-input",type:"checkbox"},null,512),[[t5,a.value.SaveConfig]]),Zd])])]),f("div",Yd,[f("fieldset",null,[Gd,f("div",Xd,[f("label",Qd,$(z.$t("modals.interfaceedit.defaults.endpoint")),1),g1(f("input",{"onUpdate:modelValue":H[18]||(H[18]=p=>a.value.PeerDefEndpoint=p),class:"form-control",placeholder:"Endpoint Addresses",type:"text"},null,512),[[S1,a.value.PeerDefEndpoint]]),Jd]),f("div",cz,[f("label",ez,$(z.$t("modals.interfaceedit.defaults.networks")),1),g1(f("input",{"onUpdate:modelValue":H[19]||(H[19]=p=>a.value.PeerDefNetworkStr=p),class:"form-control",placeholder:"Network Addresses",type:"text"},null,512),[[S1,a.value.PeerDefNetworkStr]]),tz]),f("div",sz,[f("label",lz,$(z.$t("modals.interfaceedit.defaults.allowedips")),1),g1(f("input",{"onUpdate:modelValue":H[20]||(H[20]=p=>a.value.PeerDefAllowedIPsStr=p),class:"form-control",placeholder:"Listen Port",type:"text"},null,512),[[S1,a.value.PeerDefAllowedIPsStr]])]),f("div",nz,[f("label",rz,$(z.$t("modals.interfaceedit.defaults.dns")),1),g1(f("input",{"onUpdate:modelValue":H[21]||(H[21]=p=>a.value.PeerDefDnsStr=p),class:"form-control",placeholder:"DNS Servers",type:"text"},null,512),[[S1,a.value.PeerDefDnsStr]])]),f("div",az,[f("label",iz,$(z.$t("modals.interfaceedit.defaults.dnssearch")),1),g1(f("input",{"onUpdate:modelValue":H[22]||(H[22]=p=>a.value.PeerDefDnsSearchStr=p),class:"form-control",placeholder:"DNS Search prefix",type:"text"},null,512),[[S1,a.value.PeerDefDnsSearchStr]])]),f("div",oz,[f("div",fz,[f("label",uz,$(z.$t("modals.interfaceedit.defaults.mtu")),1),g1(f("input",{"onUpdate:modelValue":H[23]||(H[23]=p=>a.value.PeerDefMtu=p),class:"form-control",placeholder:"Client MTU (0 = default)",type:"number"},null,512),[[S1,a.value.PeerDefMtu]])]),f("div",hz,[f("label",mz,$(z.$t("modals.interfaceedit.defaults.firewallmark")),1),g1(f("input",{"onUpdate:modelValue":H[24]||(H[24]=p=>a.value.PeerDefFirewallMark=p),class:"form-control",placeholder:"Firewall Mark (0 = default)",type:"number"},null,512),[[S1,a.value.PeerDefFirewallMark]])])]),f("div",dz,[f("div",zz,[f("label",Cz,$(z.$t("modals.interfaceedit.defaults.routingtable")),1),g1(f("input",{"onUpdate:modelValue":H[25]||(H[25]=p=>a.value.PeerDefRoutingTable=p),class:"form-control",placeholder:"Routing Table (0 = default)",type:"number"},null,512),[[S1,a.value.PeerDefRoutingTable]])]),f("div",vz,[f("label",Hz,$(z.$t("modals.interfaceedit.defaults.keepalive")),1),g1(f("input",{"onUpdate:modelValue":H[26]||(H[26]=p=>a.value.PeerDefPersistentKeepalive=p),class:"form-control",placeholder:"Persistent Keepalive (0 = default)",type:"number"},null,512),[[S1,a.value.PeerDefPersistentKeepalive]])])])]),f("fieldset",null,[Vz,f("div",Mz,[f("label",pz,$(z.$t("modals.interfaceedit.defaults.preup")),1),g1(f("textarea",{"onUpdate:modelValue":H[27]||(H[27]=p=>a.value.PeerDefPreUp=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PeerDefPreUp]])]),f("div",Lz,[f("label",gz,$(z.$t("modals.interfaceedit.defaults.postup")),1),g1(f("textarea",{"onUpdate:modelValue":H[28]||(H[28]=p=>a.value.PeerDefPostUp=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PeerDefPostUp]])]),f("div",bz,[f("label",_z,$(z.$t("modals.interfaceedit.defaults.predown")),1),g1(f("textarea",{"onUpdate:modelValue":H[29]||(H[29]=p=>a.value.PeerDefPreDown=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PeerDefPreDown]])]),f("div",yz,[f("label",Sz,$(z.$t("modals.interfaceedit.defaults.postdown")),1),g1(f("textarea",{"onUpdate:modelValue":H[30]||(H[30]=p=>a.value.PeerDefPostDown=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PeerDefPostDown]])])])])])]),footer:V2(()=>[f("div",wz,[t.interfaceId!=="#NEW#"?(C1(),b1("button",{key:0,class:"btn btn-danger me-1",type:"button",onClick:i2(C,["prevent"])},"Delete",8,Ez)):R1("",!0)]),f("button",{class:"btn btn-primary me-1",type:"button",onClick:i2(u,["prevent"])},"Save",8,kz),f("button",{class:"btn btn-secondary",type:"button",onClick:i2(o,["prevent"])},"Discard",8,Az)]),_:1},8,["title","visible"]))}},Tz={class:"page-header row"},Oz={class:"col-12 col-lg-8"},xz={class:"col-12 col-lg-4 text-end"},Iz=f("div",{class:"form-group"},null,-1),$z={class:"form-group"},Nz={class:"input-group mb-3"},Dz=f("i",{class:"fa-solid fa-plus-circle"},null,-1),Rz=[Dz],Fz=["disabled"],jz={key:0,value:"nothing"},Uz=["value"],qz={key:0,class:"row"},Wz={class:"col-lg-12"},Bz={class:"mt-5"},Kz={key:1,class:"row"},Zz={class:"col-lg-12"},Yz={class:"card border-secondary mb-4",style:{"min-height":"15rem"}},Gz={class:"card-header"},Xz={class:"row"},Qz={class:"col-12 col-lg-8"},Jz={class:"col-12 col-lg-4 text-lg-end"},cC=Pa('',3),eC=f("i",{class:"fas fa-cog"},null,-1),tC=[eC],sC={class:"card-body d-flex flex-column"},lC={key:0,class:"row"},nC={class:"col-sm-6"},rC={class:"table table-sm table-borderless device-status-table"},aC={class:"col-sm-6"},iC={class:"table table-sm table-borderless device-status-table"},oC={key:1,class:"row"},fC={class:"col-sm-6"},uC={class:"table table-sm table-borderless device-status-table"},hC={class:"col-sm-6"},mC={class:"table table-sm table-borderless device-status-table"},dC={key:2,class:"row"},zC={class:"col-sm-6"},CC={class:"table table-sm table-borderless device-status-table"},vC={class:"col-sm-6"},HC={class:"table table-sm table-borderless device-status-table"},VC={key:2,class:"mt-4 row"},MC={class:"col-12 col-lg-5"},pC={key:0,class:"mt-2"},LC={key:1,class:"mt-2"},gC={class:"col-12 col-lg-4 text-lg-end"},bC={class:"form-group d-inline"},_C={class:"input-group mb-3"},yC=f("button",{class:"input-group-text btn btn-primary",title:"Search"},[f("i",{class:"fa-solid fa-search"})],-1),SC={class:"col-12 col-lg-3 text-lg-end"},wC={key:0,class:"btn btn-primary",href:"#",title:"Send mail to all peers"},EC=f("i",{class:"fa fa-paper-plane"},null,-1),kC=[EC],AC=f("a",{class:"btn btn-primary ms-2",href:"#",title:"Add multiple peers"},[f("i",{class:"fa fa-plus me-1"}),f("i",{class:"fa fa-users"})],-1),PC=f("i",{class:"fa fa-plus me-1"},null,-1),TC=f("i",{class:"fa fa-user"},null,-1),OC=[PC,TC],xC={key:3,class:"mt-2 table-responsive"},IC={key:0},$C={key:1,id:"peerTable",class:"table table-sm"},NC=f("th",{scope:"col"},[f("input",{id:"flexCheckDefault",class:"form-check-input",title:"Select all",type:"checkbox",value:""})],-1),DC={scope:"col"},RC={scope:"col"},FC={scope:"col"},jC={scope:"col"},UC={key:0,scope:"col"},qC={scope:"col"},WC=f("th",{scope:"col"},null,-1),BC=f("th",{scope:"row"},[f("input",{id:"flexCheckDefault",class:"form-check-input",type:"checkbox",value:""})],-1),KC={key:0},ZC={class:"text-center"},YC=["onClick"],GC=f("i",{class:"fas fa-eye me-2"},null,-1),XC=[GC],QC=["onClick"],JC=f("i",{class:"fas fa-cog"},null,-1),cv=[JC],ev={key:4},tv={key:5,class:"mt-3"},sv={class:"row"},lv={class:"col-6"},nv={class:"pagination pagination-sm"},rv=["onClick"],av={class:"col-6"},iv={class:"form-group row"},ov={class:"col-sm-6 col-form-label text-end",for:"paginationSelector"},fv={class:"col-sm-6"},uv=f("option",{value:"10"},"10",-1),hv=f("option",{value:"25"},"25",-1),mv=f("option",{value:"50"},"50",-1),dv=f("option",{value:"100"},"100",-1),zv={value:"999999999"},ws={__name:"InterfaceView",setup(c){const e=l8(),t=x7(),s=a2(""),l=a2(""),n=a2("");return s8(async()=>{await e.LoadInterfaces(),await t.LoadPeers()}),(r,a)=>(C1(),b1(Y1,null,[W1($u,{peerId:s.value,visible:s.value!=="",onClose:a[0]||(a[0]=i=>s.value="")},null,8,["peerId","visible"]),W1(Km,{peerId:l.value,visible:l.value!=="",onClose:a[1]||(a[1]=i=>l.value="")},null,8,["peerId","visible"]),W1(Pz,{interfaceId:n.value,visible:n.value!=="",onClose:a[2]||(a[2]=i=>n.value="")},null,8,["interfaceId","visible"]),f("div",Tz,[f("div",Oz,[f("h1",null,$(r.$t("interfaces.h1")),1)]),f("div",xz,[Iz,f("div",$z,[f("div",Nz,[f("button",{class:"input-group-text btn btn-primary",title:"Add new interface",onClick:a[3]||(a[3]=i2(i=>n.value="#NEW#",["prevent"]))},Rz),g1(f("select",{"onUpdate:modelValue":a[4]||(a[4]=i=>Z(e).selected=i),disabled:Z(e).Count===0,class:"form-select",onChange:a[5]||(a[5]=i=>Z(t).LoadPeers())},[Z(e).Count===0?(C1(),b1("option",jz,$(r.$t("interfaces.notAvailable")),1)):R1("",!0),(C1(!0),b1(Y1,null,O4(Z(e).All,i=>(C1(),b1("option",{key:i.Identifier,value:i.Identifier},$(i.Identifier),9,Uz))),128))],40,Fz),[[F0,Z(e).selected]])])])])]),Z(e).Count===0?(C1(),b1("div",qz,[f("div",Wz,[f("div",Bz,[f("h4",null,$(r.$t("interfaces.noInterface.h1")),1),f("p",null,$(r.$t("interfaces.noInterface.message")),1)])])])):R1("",!0),Z(e).Count!==0?(C1(),b1("div",Kz,[f("div",Zz,[f("div",Yz,[f("div",Gz,[f("div",Xz,[f("div",Qz,[r2($(r.$t("interfaces.statusBox.h1"))+" ",1),f("strong",null,$(Z(e).GetSelected.Identifier),1),r2(" ("+$(Z(e).GetSelected.Mode)+" "+$(r.$t("interfaces.statusBox.mode"))+") ",1)]),f("div",Jz,[cC,f("a",{class:"ms-5 btn-link",href:"#",title:"Edit interface settings",onClick:a[6]||(a[6]=i2(i=>n.value=Z(e).GetSelected.Identifier,["prevent"]))},tC)])])]),f("div",sC,[Z(e).GetSelected.Mode==="server"?(C1(),b1("div",lC,[f("div",nC,[f("table",rC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.key"))+":",1),f("td",null,$(Z(e).GetSelected.PublicKey),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.endpoint"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefEndpoint),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.port"))+":",1),f("td",null,$(Z(e).GetSelected.ListenPort),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.peers"))+":",1),f("td",null,$(Z(e).GetSelected.EnabledPeers),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.totalPeers"))+":",1),f("td",null,$(Z(e).GetSelected.TotalPeers),1)])])])]),f("div",aC,[f("table",iC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.ip"))+":",1),f("td",null,$(Z(e).GetSelected.Addresses),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.allowedIP"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefAllowedIPsStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.dnsServers"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefDnsStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.mtu"))+":",1),f("td",null,$(Z(e).GetSelected.Mtu),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.intervall"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefPersistentKeepalive),1)])])])])])):R1("",!0),Z(e).GetSelected.Mode==="client"?(C1(),b1("div",oC,[f("div",fC,[f("table",uC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.key"))+":",1),f("td",null,$(Z(e).GetSelected.PublicKey),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.endpoint"))+":",1),f("td",null,$(Z(e).GetSelected.InterfacePeers),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.totalPeers"))+":",1),f("td",null,$(Z(e).GetSelected.TotalPeers),1)])])])]),f("div",hC,[f("table",mC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.ip"))+":",1),f("td",null,$(Z(e).GetSelected.AddressStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.dnsServers"))+":",1),f("td",null,$(Z(e).GetSelected.DnsStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.mtu"))+":",1),f("td",null,$(Z(e).GetSelected.Mtu),1)])])])])])):R1("",!0),Z(e).GetSelected.Mode==="any"?(C1(),b1("div",dC,[f("div",zC,[f("table",CC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.key"))+":",1),f("td",null,$(Z(e).GetSelected.PublicKey),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.endpoint"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefEndpoint),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.port"))+":",1),f("td",null,$(Z(e).GetSelected.ListenPort),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.peers"))+":",1),f("td",null,$(Z(e).GetSelected.EnabledPeers),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.totalPeers"))+":",1),f("td",null,$(Z(e).GetSelected.TotalPeers),1)])])])]),f("div",vC,[f("table",HC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.ip"))+":",1),f("td",null,$(Z(e).GetSelected.Addresses),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.allowedIP"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefAllowedIPsStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.dnsServers"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefDnsStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.mtu"))+":",1),f("td",null,$(Z(e).GetSelected.Mtu),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.intervall"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefPersistentKeepalive),1)])])])])])):R1("",!0)])])])])):R1("",!0),Z(e).Count!==0?(C1(),b1("div",VC,[f("div",MC,[Z(e).GetSelected.Mode==="server"?(C1(),b1("h2",pC,$(r.$t("interfaces.h2")),1)):(C1(),b1("h2",LC,$(r.$t("interfaces.h2-client")),1))]),f("div",gC,[f("div",bC,[f("div",_C,[g1(f("input",{"onUpdate:modelValue":a[7]||(a[7]=i=>Z(t).filter=i),class:"form-control",placeholder:"Search...",type:"text",onKeyup:a[8]||(a[8]=(...i)=>Z(t).afterPageSizeChange&&Z(t).afterPageSizeChange(...i))},null,544),[[S1,Z(t).filter]]),yC])])]),f("div",SC,[Z(e).GetSelected.Mode==="server"&&Z(t).Count!==0?(C1(),b1("a",wC,kC)):R1("",!0),AC,f("a",{class:"btn btn-primary ms-2",href:"#",title:"Add a peer",onClick:a[9]||(a[9]=i2(i=>l.value="#NEW#",["prevent"]))},OC)])])):R1("",!0),Z(e).Count!==0?(C1(),b1("div",xC,[Z(t).Count===0?(C1(),b1("div",IC,[f("h4",null,$(r.$t("interfaces.noPeerSelect.h4")),1),f("p",null,$(r.$t("interfaces.noPeerSelect.message")),1)])):R1("",!0),Z(t).Count!==0?(C1(),b1("table",$C,[f("thead",null,[f("tr",null,[NC,f("th",DC,$(r.$t("interfaces.tableHeadings[0]")),1),f("th",RC,$(r.$t("interfaces.tableHeadings[1]")),1),f("th",FC,$(r.$t("interfaces.tableHeadings[2]")),1),f("th",jC,$(r.$t("interfaces.tableHeadings[3]")),1),Z(e).GetSelected.Mode==="client"?(C1(),b1("th",UC,$(r.$t("interfaces.tableHeadings[4]")),1)):R1("",!0),f("th",qC,$(r.$t("interfaces.tableHeadings[5]")),1),WC])]),f("tbody",null,[(C1(!0),b1(Y1,null,O4(Z(t).FilteredAndPaged,i=>(C1(),b1("tr",{key:i.Identifier},[BC,f("td",null,$(i.DisplayName),1),f("td",null,$(i.Identifier),1),f("td",null,$(i.UserIdentifier),1),f("td",null,[(C1(!0),b1(Y1,null,O4(i.Addresses,o=>(C1(),b1("span",{key:o,class:"badge rounded-pill bg-light"},$(o),1))),128))]),Z(e).GetSelected.Mode==="client"?(C1(),b1("td",KC,$(i.Endpoint),1)):R1("",!0),f("td",null,$(i.LastConnected),1),f("td",ZC,[f("a",{href:"#",title:"Show peer",onClick:i2(o=>s.value=i.Identifier,["prevent"])},XC,8,YC),f("a",{href:"#",title:"Edit peer",onClick:i2(o=>l.value=i.Identifier,["prevent"])},cv,8,QC)])]))),128))])])):R1("",!0)])):R1("",!0),Z(e).Count!==0?(C1(),b1("hr",ev)):R1("",!0),Z(e).Count!==0?(C1(),b1("div",tv,[f("div",sv,[f("div",lv,[f("ul",nv,[f("li",{class:b2([{disabled:Z(t).pageOffset===0},"page-item"])},[f("a",{class:"page-link",onClick:a[10]||(a[10]=(...i)=>Z(t).previousPage&&Z(t).previousPage(...i))},"«")],2),(C1(!0),b1(Y1,null,O4(Z(t).pages,i=>(C1(),b1("li",{key:i,class:b2([{active:Z(t).currentPage===i},"page-item"])},[f("a",{class:"page-link",onClick:o=>Z(t).gotoPage(i)},$(i),9,rv)],2))),128)),f("li",{class:b2([{disabled:!Z(t).hasNextPage},"page-item"])},[f("a",{class:"page-link",onClick:a[11]||(a[11]=(...i)=>Z(t).nextPage&&Z(t).nextPage(...i))},"»")],2)])]),f("div",av,[f("div",iv,[f("label",ov,$(r.$t("interfaces.pagination.size"))+":",1),f("div",fv,[g1(f("select",{"onUpdate:modelValue":a[12]||(a[12]=i=>Z(t).pageSize=i),class:"form-select",onClick:a[13]||(a[13]=i=>Z(t).afterPageSizeChange())},[uv,hv,mv,dv,f("option",zv,$(r.$t("interfaces.pagination.all")),1)],512),[[F0,Z(t).pageSize,void 0,{number:!0}]])])])])])])):R1("",!0)],64))}},Cv=Object.freeze(Object.defineProperty({__proto__:null,default:ws},Symbol.toStringTag,{value:"Module"})),R4=Oo({history:Xi(),routes:[{path:"/",name:"home",component:Kf},{path:"/login",name:"login",component:pu},{path:"/interface",name:"interface",component:ws},{path:"/interfaces",name:"interfaces",component:()=>qc(()=>Promise.resolve().then(()=>Cv),void 0)},{path:"/users",name:"users",component:()=>qc(()=>import("./UserView-f9bf06a4.js"),[])}],linkActiveClass:"active",linkExactActiveClass:"exact-active"});R4.beforeEach(async c=>{const e=o6();if("wgLoginState"in c.query&&!e.IsAuthenticated){const l=c.query.wgLoginState,n=e.ReturnUrl;if(console.log("Oauth login callback:",l),l==="success")try{const r=await e.LoadSession();return console.log("Oauth login completed for UID:",r),console.log("Continuing to:",n),t2({title:"Logged in",text:"Authentication suceeded!",type:"success"}),e.ResetReturnUrl(),n}catch{return t2({title:"Login failed!",text:"Oauth session is invalid!",type:"error"}),"/login"}else return t2({title:"Login failed!",text:"Authentication via Oauth failed!",type:"error"}),"/login"}if(!["/","/login"].includes(c.path)&&!e.IsAuthenticated)return e.SetReturnUrl(c.fullPath),"/login"});const o6=L5({id:"auth",state:()=>({user:JSON.parse(localStorage.getItem("user")),providers:[],returnUrl:localStorage.getItem("returnUrl")}),getters:{UserIdentifier:c=>{var e;return((e=c.user)==null?void 0:e.Identifier)||"unknown"},User:c=>c.user,LoginProviders:c=>c.providers,IsAuthenticated:c=>c.user!=null,IsAdmin:c=>{var e;return((e=c.user)==null?void 0:e.IsAdmin)||!1},ReturnUrl:c=>c.returnUrl||"/"},actions:{SetReturnUrl(c){this.returnUrl=c,localStorage.setItem("returnUrl",c)},ResetReturnUrl(){this.returnUrl=null,localStorage.removeItem("returnUrl")},async LoadProviders(){F2.get("/auth/providers").then(c=>this.providers=c).catch(c=>{this.providers=[],console.log("Failed to load auth providers: ",c),t2({title:"Backend Connection Failure",text:"Failed to load external authentication providers!"})})},async LoadSession(){return F2.get("/auth/session").then(c=>c.LoggedIn===!0?(this.ResetReturnUrl(),this.setUserInfo(c),c.UserIdentifier):(this.setUserInfo(null),Promise.reject(new Error("session not authenticated")))).catch(c=>(this.setUserInfo(null),Promise.reject(c)))},async Login(c,e){return F2.post("/auth/login",{username:c,password:e}).then(t=>(this.ResetReturnUrl(),this.setUserInfo(t),t.Identifier)).catch(t=>(console.log("Login failed:",t),this.setUserInfo(null),Promise.reject(new Error("login failed"))))},async Logout(){this.setUserInfo(null),this.ResetReturnUrl();try{await F2.post("/auth/logout")}catch(c){console.log("Logout request failed:",c)}t2({title:"Logged Out",text:"Logout successful!",type:"warn"}),await R4.push("/login")},setUserInfo(c){c?("UserIdentifier"in c?this.user={Identifier:c.UserIdentifier,Firstname:c.UserFirstname,Lastname:c.UserLastname,Email:c.UserEmail,IsAdmin:c.IsAdmin}:this.user={Identifier:c.Identifier,Firstname:c.Firstname,Lastname:c.Lastname,Email:c.Email,IsAdmin:c.IsAdmin},localStorage.setItem("user",JSON.stringify(this.user))):(this.user=null,localStorage.removeItem("user"))}}});const vv={class:"navbar navbar-expand-lg navbar-dark bg-primary"},Hv={class:"container-fluid"},Vv=f("a",{class:"navbar-brand",href:"/"},[f("img",{alt:"WireGuard Portal",src:Ai})],-1),Mv=f("button",{"aria-controls":"navbarColor01","aria-expanded":"false","aria-label":"Toggle navigation",class:"navbar-toggler","data-bs-target":"#navbarTop","data-bs-toggle":"collapse",type:"button"},[f("span",{class:"navbar-toggler-icon"})],-1),pv={id:"navbarTop",class:"collapse navbar-collapse"},Lv={class:"navbar-nav me-auto"},gv={class:"nav-item"},bv={key:0,class:"nav-item"},_v={key:1,class:"nav-item"},yv={class:"navbar-nav d-flex justify-content-end"},Sv={key:0,class:"nav-item dropdown"},wv={"aria-expanded":"false","aria-haspopup":"true",class:"nav-link dropdown-toggle","data-bs-toggle":"dropdown",href:"#",role:"button"},Ev={class:"dropdown-menu"},kv={class:"dropdown-item",href:"/user/profile"},Av=f("i",{class:"fas fa-user"},null,-1),Pv=f("div",{class:"dropdown-divider"},null,-1),Tv=f("i",{class:"fas fa-sign-out-alt"},null,-1),Ov={key:1,class:"nav-item"},xv=f("i",{class:"fas fa-sign-in-alt fa-sm fa-fw me-2"},null,-1),Iv={class:"container mt-5 flex-shrink-0"},$v={class:"page-footer mt-auto"},Nv={class:"container mt-5"},Dv={class:"row align-items-center"},Rv=f("div",{class:"col-6"},[r2("Powered by "),f("img",{alt:"Vue.JS",height:"20",src:Pi})],-1),Fv={class:"col-6 text-end"},jv={"aria-label":"{{ $t('menu.lang') }}",class:"btn-group",role:"group"},Uv={class:"btn-group",role:"group"},qv={"aria-expanded":"false","aria-haspopup":"true",class:"btn btn btn-secondary pe-0","data-bs-toggle":"dropdown",type:"button"},Wv={"aria-labelledby":"btnGroupDrop3",class:"dropdown-menu",style:{}},Bv=f("span",{class:"fi fi-us"},null,-1),Kv=f("span",{class:"fi fi-de"},null,-1),Zv=f("span",{class:"fi fi-es"},null,-1),Yv={__name:"App",setup(c){const e=V3().appContext.config.globalProperties,t=o6(),s=Hs();s8(async()=>{console.log("Starting WireGuard Portal frontend..."),await s.LoadSecurityProperties(),await t.LoadProviders();let r=t.IsAuthenticated;try{await t.LoadSession()}catch{r&&await t.Logout()}console.log("WireGuard Portal ready!")});const l=function(r){e.$i18n.locale!==r&&(localStorage.setItem("wgLang",r),e.$i18n.locale=r)},n=F1(()=>{let r=e.$i18n.locale.toLowerCase();return r==="en"&&(r="us"),"fi-"+r});return(r,a)=>{const i=Pt("notifications");return C1(),b1(Y1,null,[W1(i,{duration:3e3,"ignore-duplicates":!0,position:"top right"}),f("nav",vv,[f("div",Hv,[Vv,Mv,f("div",pv,[f("ul",Lv,[f("li",gv,[W1(Z(w6),{to:{name:"home"},class:"nav-link"},{default:V2(()=>[r2($(r.$t("menu.home")),1)]),_:1})]),Z(t).IsAuthenticated&&Z(t).IsAdmin?(C1(),b1("li",bv,[W1(Z(w6),{to:{name:"interfaces"},class:"nav-link"},{default:V2(()=>[r2($(r.$t("menu.interfaces")),1)]),_:1})])):R1("",!0),Z(t).IsAuthenticated&&Z(t).IsAdmin?(C1(),b1("li",_v,[W1(Z(w6),{to:{name:"users"},class:"nav-link"},{default:V2(()=>[r2($(r.$t("menu.users")),1)]),_:1})])):R1("",!0)]),f("div",yv,[Z(t).IsAuthenticated?(C1(),b1("div",Sv,[f("a",wv,$(Z(t).User.Firstname)+" "+$(Z(t).User.Lastname),1),f("div",Ev,[f("a",kv,[Av,r2(" "+$(r.$t("menu.profile")),1)]),Pv,f("a",{class:"dropdown-item",href:"#",onClick:a[0]||(a[0]=i2((...o)=>Z(t).Logout&&Z(t).Logout(...o),["prevent"]))},[Tv,r2(" "+$(r.$t("menu.logout")),1)])])])):R1("",!0),Z(t).IsAuthenticated?R1("",!0):(C1(),b1("div",Ov,[W1(Z(w6),{to:{name:"login"},class:"nav-link"},{default:V2(()=>[xv,r2($(r.$t("menu.login")),1)]),_:1})]))])])])]),f("div",Iv,[W1(Z(Cs))]),f("footer",$v,[f("div",Nv,[f("div",Dv,[Rv,f("div",Fv,[f("div",jv,[f("div",Uv,[f("button",qv,[f("span",{class:b2([Z(n),"fi"])},null,2)]),f("div",Wv,[f("a",{class:"dropdown-item",href:"#",onClick:a[1]||(a[1]=i2(o=>l("en"),["prevent"]))},[Bv,r2(" English")]),f("a",{class:"dropdown-item",href:"#",onClick:a[2]||(a[2]=i2(o=>l("de"),["prevent"]))},[Kv,r2(" Deutsch")]),f("a",{class:"dropdown-item",href:"#",onClick:a[3]||(a[3]=i2(o=>l("es"),["prevent"]))},[Zv,r2(" Español")])])])])])])])])],64)}}},Gv="Hallo Welt!",Xv={home:"Home",interfaces:"Schnittstellen",firstname:"Vorname",surname:"Nachname",login:"Anmelden",logout:"Abmelden",admin:"Verwaltung",user:"Nutzer",profile:"Profil",lang:"Sprache umschalten"},Qv={h1:"WireGuard® VPN Portal",abstract:"WireGuard® ist ein extrem einfaches, aber dennoch schnelles und modernes VPN, das modernste Kryptographie nutzt. Es zielt darauf ab, schneller, einfacher, schlanker und nützlicher als IPsec zu sein, während es die massiven Kopfschmerzen vermeidet. Es soll wesentlich leistungsfähiger sein als OpenVPN.",info:"Informationen",installation:{h1:"VPN Installation",h2:"Installation",instruct:"Die Installationsanweisungen für die Client-Software finden Sie auf der offiziellen WireGuard-Website.",btn:"Anleitung öffnen"},"about-wg":{instruct:"WireGuard® ist ein extrem einfaches, aber schnelles und modernes VPN, das modernste Kryptographie verwendet.",h1:"Über WireGuard",h2:"Über",btn:"Details"},"about-portal":{instruct:"WireGuard Portal ist ein einfaches, webbasiertes Konfigurationsportal für WireGuard.",h1:"Über WireGuard Portal",h2:"WireGuard-Portal",btn:"Details"},profiles:{h1:"VPN Profile",abstract:"Über Ihr Benutzerprofil können Sie auf Ihre persönlichen VPN-Konfigurationen zugreifen und diese herunterladen.",instruct:"Um alle Ihre konfigurierten Profile zu finden, klicken Sie auf die Schaltfläche unten.",btn:"Mein Profil öffnen"},admin:{h1:"Verwaltungsbereich",abstract:"Im Administrationsbereich können Sie VPN-Zugänge und die Serverschnittstelle sowie die Benutzer, die sich am VPN-Portal anmelden dürfen, verwalten.",instruct:"Um alle Ihre konfigurierten Profile zu finden, klicken Sie auf die Schaltfläche unten.","btn-1":"Serververwaltung öffnen","btn-2":"Benutzerverwaltung öffnen"}},Jv={h1:"Schnittstellenverwaltung",h2:"Aktuelle VPN-Geräte","h2-client":"Aktuelle Endpunkte",tableHeadings:["Name","Kennung","Benutzer","IPs","Endpunkt","Handschlag"],noInterface:{h1:"Keine Schnittstellen gefunden...",message:"Klicken Sie auf die Plus-Schaltfläche oben, um eine neue WireGuard-Schnittstelle zu erstellen."},notAvailable:"Keine Schnittstelle verfügbar",statusBox:{h1:"Schnittstellenstatus für",key:"Öffentlicher Schlüssel",mode:"Modus",endpoint:"Öffentlicher Endpunkt",port:"Lauschender Port",peers:"Aktivierte Zugänge",totalPeers:"Alle Zugänge",ip:"IP-Adresse",allowedIP:"Standardmäßig erlaubte IPs",dnsServers:"DNS-Server",mtu:"Vorgegebene MTU",intervall:"Standard-Keepalive-Intervall"},noPeerSelect:{h4:"Keine Zugänge für die ausgewählte Schnittstelle...",message:"Klicken Sie auf die Plus-Schaltfläche oben, um eine neue VPN-Schnittstelle zu erstellen."},pagination:{size:"Anzahl",all:"Alle (langsam)"}},cH={please:"Bitte melden Sie sich an",username:"Benutzername",userMessage:"Bitte geben Sie Ihren Benutzernamen ein",pass:"Kennwort",passMessage:"Bitte geben Sie Ihr Passwort ein",btn:"Sign in"},eH={hello:Gv,menu:Xv,home:Qv,interfaces:Jv,login:cH},tH="Hello World!",sH={home:"Home",interfaces:"Interfaces",users:"Users",firstname:"Firstname",lastname:"Lastname",login:"Login",lang:"Toggle Language"},lH={h1:"WireGuard® VPN Portal",info:"More Information",abstract:"WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN.",installation:{instruct:"Installation instructions for client software can be found on the official WireGuard website.",h1:"WireGuard Installation",h2:"Installation",btn:"Open Instructions"},"about-wg":{instruct:"WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography.",h1:"About WireGuard",h2:"About",btn:"More"},"about-portal":{instruct:"WireGuard Portal is a simple, web based configuration portal for WireGuard.",h1:"About WireGuard Portal",h2:"WireGuard Portal",btn:"More"},profiles:{h1:"VPN Profiles",abstract:"You can access and download your personal VPN configurations via your Userprofile.",instruct:"To find all your configured profiles click on the button below.",btn:"Open my profile"},admin:{h1:"Administration Area",abstract:"In the administration area you can manage WireGuard peers and the server interface as well as users that are allowed to log in to the WireGuard Portal.",instruct:"To find all your configured profiles click on the button below.","btn-1":"Open Server Administration","btn-2":"Open User Administration"}},nH={h1:"Interface Administration",h2:"Current VPN Peers","h2-client":"Current Endpoints",tableHeadings:["Name","Identifier","User","IPs","Endpoint","Handshake"],noInterface:{h1:"No interfaces found...",message:"Click the plus button above to create a new WireGuard interface."},notAvailable:"No Interface available",statusBox:{h1:"Interface status for",mode:"mode",key:"Public Key",endpoint:"Public Endpoint",port:"Listening Port",peers:"Enabled Peers",totalPeers:"Total Peers",ip:"IP Address",allowedIP:"Default allowed IPs",dnsServers:"DNS Servers",mtu:"Default MTU",interval:"Default Keepalive Interval"},noPeerSelect:{h4:"No peers for the selected interface...",message:"Click the plus button above to create a new WireGuard interface."},pagination:{size:"Number of Elements",all:"All (slow)"},peer:{new:"Create new peer",edit:"Edit peer"},interface:{new:"Create new interface",edit:"Edit interface"},endpoint:{new:"Create new endpoint",edit:"Edit endpoint"}},rH={please:"Please sign in",username:"Username",userMessage:"Please enter your username",pass:"Password",passMessage:"Please enter your password",btn:"Sign in"},aH={h1:"User Administration",id:"ID",email:"eMail",firstname:"Firstname",lastname:"Lastname",source:"Source",peers:"Peers",admin:"Admin",addUser:"Add User",addMulti:"Add Multiple Users"},iH={peeredit:{privatekey:"Private Key"}},oH={hello:tH,menu:sH,home:lH,interfaces:nH,login:rH,user:aH,modals:iH},fH="Hola mundo!",uH={hello:fH};function hH(){let c=localStorage.getItem("wgLang");return c||(c="en"),c}const mH=nm({legacy:!1,globalInjection:!0,allowComposition:!0,locale:hH(),fallbackLocale:"en",messages:{de:eH,en:oH,es:uH}});var p2="top",E2="bottom",k2="right",L2="left",S5="auto",f6=[p2,E2,k2,L2],H4="start",X4="end",Es="clippingParents",j7="viewport",A4="popper",ks="reference",t7=f6.reduce(function(c,e){return c.concat([e+"-"+H4,e+"-"+X4])},[]),U7=[].concat(f6,[S5]).reduce(function(c,e){return c.concat([e,e+"-"+H4,e+"-"+X4])},[]),As="beforeRead",Ps="read",Ts="afterRead",Os="beforeMain",xs="main",Is="afterMain",$s="beforeWrite",Ns="write",Ds="afterWrite",Rs=[As,Ps,Ts,Os,xs,Is,$s,Ns,Ds];function n3(c){return c?(c.nodeName||"").toLowerCase():null}function $2(c){if(c==null)return window;if(c.toString()!=="[object Window]"){var e=c.ownerDocument;return e&&e.defaultView||window}return c}function V4(c){var e=$2(c).Element;return c instanceof e||c instanceof Element}function x2(c){var e=$2(c).HTMLElement;return c instanceof e||c instanceof HTMLElement}function q7(c){if(typeof ShadowRoot>"u")return!1;var e=$2(c).ShadowRoot;return c instanceof e||c instanceof ShadowRoot}function dH(c){var e=c.state;Object.keys(e.elements).forEach(function(t){var s=e.styles[t]||{},l=e.attributes[t]||{},n=e.elements[t];!x2(n)||!n3(n)||(Object.assign(n.style,s),Object.keys(l).forEach(function(r){var a=l[r];a===!1?n.removeAttribute(r):n.setAttribute(r,a===!0?"":a)}))})}function zH(c){var e=c.state,t={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,t.popper),e.styles=t,e.elements.arrow&&Object.assign(e.elements.arrow.style,t.arrow),function(){Object.keys(e.elements).forEach(function(s){var l=e.elements[s],n=e.attributes[s]||{},r=Object.keys(e.styles.hasOwnProperty(s)?e.styles[s]:t[s]),a=r.reduce(function(i,o){return i[o]="",i},{});!x2(l)||!n3(l)||(Object.assign(l.style,a),Object.keys(n).forEach(function(i){l.removeAttribute(i)}))})}}const W7={name:"applyStyles",enabled:!0,phase:"write",fn:dH,effect:zH,requires:["computeStyles"]};function t3(c){return c.split("-")[0]}var v4=Math.max,a5=Math.min,Q4=Math.round;function s7(){var c=navigator.userAgentData;return c!=null&&c.brands?c.brands.map(function(e){return e.brand+"/"+e.version}).join(" "):navigator.userAgent}function Fs(){return!/^((?!chrome|android).)*safari/i.test(s7())}function J4(c,e,t){e===void 0&&(e=!1),t===void 0&&(t=!1);var s=c.getBoundingClientRect(),l=1,n=1;e&&x2(c)&&(l=c.offsetWidth>0&&Q4(s.width)/c.offsetWidth||1,n=c.offsetHeight>0&&Q4(s.height)/c.offsetHeight||1);var r=V4(c)?$2(c):window,a=r.visualViewport,i=!Fs()&&t,o=(s.left+(i&&a?a.offsetLeft:0))/l,u=(s.top+(i&&a?a.offsetTop:0))/n,C=s.width/l,z=s.height/n;return{width:C,height:z,top:u,right:o+C,bottom:u+z,left:o,x:o,y:u}}function B7(c){var e=J4(c),t=c.offsetWidth,s=c.offsetHeight;return Math.abs(e.width-t)<=1&&(t=e.width),Math.abs(e.height-s)<=1&&(s=e.height),{x:c.offsetLeft,y:c.offsetTop,width:t,height:s}}function js(c,e){var t=e.getRootNode&&e.getRootNode();if(c.contains(e))return!0;if(t&&q7(t)){var s=e;do{if(s&&c.isSameNode(s))return!0;s=s.parentNode||s.host}while(s)}return!1}function M3(c){return $2(c).getComputedStyle(c)}function CH(c){return["table","td","th"].indexOf(n3(c))>=0}function Q3(c){return((V4(c)?c.ownerDocument:c.document)||window.document).documentElement}function w5(c){return n3(c)==="html"?c:c.assignedSlot||c.parentNode||(q7(c)?c.host:null)||Q3(c)}function de(c){return!x2(c)||M3(c).position==="fixed"?null:c.offsetParent}function vH(c){var e=/firefox/i.test(s7()),t=/Trident/i.test(s7());if(t&&x2(c)){var s=M3(c);if(s.position==="fixed")return null}var l=w5(c);for(q7(l)&&(l=l.host);x2(l)&&["html","body"].indexOf(n3(l))<0;){var n=M3(l);if(n.transform!=="none"||n.perspective!=="none"||n.contain==="paint"||["transform","perspective"].indexOf(n.willChange)!==-1||e&&n.willChange==="filter"||e&&n.filter&&n.filter!=="none")return l;l=l.parentNode}return null}function a8(c){for(var e=$2(c),t=de(c);t&&CH(t)&&M3(t).position==="static";)t=de(t);return t&&(n3(t)==="html"||n3(t)==="body"&&M3(t).position==="static")?e:t||vH(c)||e}function K7(c){return["top","bottom"].indexOf(c)>=0?"x":"y"}function $6(c,e,t){return v4(c,a5(e,t))}function HH(c,e,t){var s=$6(c,e,t);return s>t?t:s}function Us(){return{top:0,right:0,bottom:0,left:0}}function qs(c){return Object.assign({},Us(),c)}function Ws(c,e){return e.reduce(function(t,s){return t[s]=c,t},{})}var VH=function(e,t){return e=typeof e=="function"?e(Object.assign({},t.rects,{placement:t.placement})):e,qs(typeof e!="number"?e:Ws(e,f6))};function MH(c){var e,t=c.state,s=c.name,l=c.options,n=t.elements.arrow,r=t.modifiersData.popperOffsets,a=t3(t.placement),i=K7(a),o=[L2,k2].indexOf(a)>=0,u=o?"height":"width";if(!(!n||!r)){var C=VH(l.padding,t),z=B7(n),H=i==="y"?p2:L2,p=i==="y"?E2:k2,E=t.rects.reference[u]+t.rects.reference[i]-r[i]-t.rects.popper[u],A=r[i]-t.rects.reference[i],L=a8(n),O=L?i==="y"?L.clientHeight||0:L.clientWidth||0:0,T=E/2-A/2,_=C[H],x=O-z[u]-C[p],K=O/2-z[u]/2+T,D=$6(_,K,x),F=i;t.modifiersData[s]=(e={},e[F]=D,e.centerOffset=D-K,e)}}function pH(c){var e=c.state,t=c.options,s=t.element,l=s===void 0?"[data-popper-arrow]":s;l!=null&&(typeof l=="string"&&(l=e.elements.popper.querySelector(l),!l)||js(e.elements.popper,l)&&(e.elements.arrow=l))}const Bs={name:"arrow",enabled:!0,phase:"main",fn:MH,effect:pH,requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function c6(c){return c.split("-")[1]}var LH={top:"auto",right:"auto",bottom:"auto",left:"auto"};function gH(c){var e=c.x,t=c.y,s=window,l=s.devicePixelRatio||1;return{x:Q4(e*l)/l||0,y:Q4(t*l)/l||0}}function ze(c){var e,t=c.popper,s=c.popperRect,l=c.placement,n=c.variation,r=c.offsets,a=c.position,i=c.gpuAcceleration,o=c.adaptive,u=c.roundOffsets,C=c.isFixed,z=r.x,H=z===void 0?0:z,p=r.y,E=p===void 0?0:p,A=typeof u=="function"?u({x:H,y:E}):{x:H,y:E};H=A.x,E=A.y;var L=r.hasOwnProperty("x"),O=r.hasOwnProperty("y"),T=L2,_=p2,x=window;if(o){var K=a8(t),D="clientHeight",F="clientWidth";if(K===$2(t)&&(K=Q3(t),M3(K).position!=="static"&&a==="absolute"&&(D="scrollHeight",F="scrollWidth")),K=K,l===p2||(l===L2||l===k2)&&n===X4){_=E2;var X=C&&K===x&&x.visualViewport?x.visualViewport.height:K[D];E-=X-s.height,E*=i?1:-1}if(l===L2||(l===p2||l===E2)&&n===X4){T=k2;var B=C&&K===x&&x.visualViewport?x.visualViewport.width:K[F];H-=B-s.width,H*=i?1:-1}}var f1=Object.assign({position:a},o&&LH),c1=u===!0?gH({x:H,y:E}):{x:H,y:E};if(H=c1.x,E=c1.y,i){var V1;return Object.assign({},f1,(V1={},V1[_]=O?"0":"",V1[T]=L?"0":"",V1.transform=(x.devicePixelRatio||1)<=1?"translate("+H+"px, "+E+"px)":"translate3d("+H+"px, "+E+"px, 0)",V1))}return Object.assign({},f1,(e={},e[_]=O?E+"px":"",e[T]=L?H+"px":"",e.transform="",e))}function bH(c){var e=c.state,t=c.options,s=t.gpuAcceleration,l=s===void 0?!0:s,n=t.adaptive,r=n===void 0?!0:n,a=t.roundOffsets,i=a===void 0?!0:a,o={placement:t3(e.placement),variation:c6(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:l,isFixed:e.options.strategy==="fixed"};e.modifiersData.popperOffsets!=null&&(e.styles.popper=Object.assign({},e.styles.popper,ze(Object.assign({},o,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:i})))),e.modifiersData.arrow!=null&&(e.styles.arrow=Object.assign({},e.styles.arrow,ze(Object.assign({},o,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:i})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})}const Z7={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:bH,data:{}};var x8={passive:!0};function _H(c){var e=c.state,t=c.instance,s=c.options,l=s.scroll,n=l===void 0?!0:l,r=s.resize,a=r===void 0?!0:r,i=$2(e.elements.popper),o=[].concat(e.scrollParents.reference,e.scrollParents.popper);return n&&o.forEach(function(u){u.addEventListener("scroll",t.update,x8)}),a&&i.addEventListener("resize",t.update,x8),function(){n&&o.forEach(function(u){u.removeEventListener("scroll",t.update,x8)}),a&&i.removeEventListener("resize",t.update,x8)}}const Y7={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:_H,data:{}};var yH={left:"right",right:"left",bottom:"top",top:"bottom"};function Z8(c){return c.replace(/left|right|bottom|top/g,function(e){return yH[e]})}var SH={start:"end",end:"start"};function Ce(c){return c.replace(/start|end/g,function(e){return SH[e]})}function G7(c){var e=$2(c),t=e.pageXOffset,s=e.pageYOffset;return{scrollLeft:t,scrollTop:s}}function X7(c){return J4(Q3(c)).left+G7(c).scrollLeft}function wH(c,e){var t=$2(c),s=Q3(c),l=t.visualViewport,n=s.clientWidth,r=s.clientHeight,a=0,i=0;if(l){n=l.width,r=l.height;var o=Fs();(o||!o&&e==="fixed")&&(a=l.offsetLeft,i=l.offsetTop)}return{width:n,height:r,x:a+X7(c),y:i}}function EH(c){var e,t=Q3(c),s=G7(c),l=(e=c.ownerDocument)==null?void 0:e.body,n=v4(t.scrollWidth,t.clientWidth,l?l.scrollWidth:0,l?l.clientWidth:0),r=v4(t.scrollHeight,t.clientHeight,l?l.scrollHeight:0,l?l.clientHeight:0),a=-s.scrollLeft+X7(c),i=-s.scrollTop;return M3(l||t).direction==="rtl"&&(a+=v4(t.clientWidth,l?l.clientWidth:0)-n),{width:n,height:r,x:a,y:i}}function Q7(c){var e=M3(c),t=e.overflow,s=e.overflowX,l=e.overflowY;return/auto|scroll|overlay|hidden/.test(t+l+s)}function Ks(c){return["html","body","#document"].indexOf(n3(c))>=0?c.ownerDocument.body:x2(c)&&Q7(c)?c:Ks(w5(c))}function N6(c,e){var t;e===void 0&&(e=[]);var s=Ks(c),l=s===((t=c.ownerDocument)==null?void 0:t.body),n=$2(s),r=l?[n].concat(n.visualViewport||[],Q7(s)?s:[]):s,a=e.concat(r);return l?a:a.concat(N6(w5(r)))}function l7(c){return Object.assign({},c,{left:c.x,top:c.y,right:c.x+c.width,bottom:c.y+c.height})}function kH(c,e){var t=J4(c,!1,e==="fixed");return t.top=t.top+c.clientTop,t.left=t.left+c.clientLeft,t.bottom=t.top+c.clientHeight,t.right=t.left+c.clientWidth,t.width=c.clientWidth,t.height=c.clientHeight,t.x=t.left,t.y=t.top,t}function ve(c,e,t){return e===j7?l7(wH(c,t)):V4(e)?kH(e,t):l7(EH(Q3(c)))}function AH(c){var e=N6(w5(c)),t=["absolute","fixed"].indexOf(M3(c).position)>=0,s=t&&x2(c)?a8(c):c;return V4(s)?e.filter(function(l){return V4(l)&&js(l,s)&&n3(l)!=="body"}):[]}function PH(c,e,t,s){var l=e==="clippingParents"?AH(c):[].concat(e),n=[].concat(l,[t]),r=n[0],a=n.reduce(function(i,o){var u=ve(c,o,s);return i.top=v4(u.top,i.top),i.right=a5(u.right,i.right),i.bottom=a5(u.bottom,i.bottom),i.left=v4(u.left,i.left),i},ve(c,r,s));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}function Zs(c){var e=c.reference,t=c.element,s=c.placement,l=s?t3(s):null,n=s?c6(s):null,r=e.x+e.width/2-t.width/2,a=e.y+e.height/2-t.height/2,i;switch(l){case p2:i={x:r,y:e.y-t.height};break;case E2:i={x:r,y:e.y+e.height};break;case k2:i={x:e.x+e.width,y:a};break;case L2:i={x:e.x-t.width,y:a};break;default:i={x:e.x,y:e.y}}var o=l?K7(l):null;if(o!=null){var u=o==="y"?"height":"width";switch(n){case H4:i[o]=i[o]-(e[u]/2-t[u]/2);break;case X4:i[o]=i[o]+(e[u]/2-t[u]/2);break}}return i}function e6(c,e){e===void 0&&(e={});var t=e,s=t.placement,l=s===void 0?c.placement:s,n=t.strategy,r=n===void 0?c.strategy:n,a=t.boundary,i=a===void 0?Es:a,o=t.rootBoundary,u=o===void 0?j7:o,C=t.elementContext,z=C===void 0?A4:C,H=t.altBoundary,p=H===void 0?!1:H,E=t.padding,A=E===void 0?0:E,L=qs(typeof A!="number"?A:Ws(A,f6)),O=z===A4?ks:A4,T=c.rects.popper,_=c.elements[p?O:z],x=PH(V4(_)?_:_.contextElement||Q3(c.elements.popper),i,u,r),K=J4(c.elements.reference),D=Zs({reference:K,element:T,strategy:"absolute",placement:l}),F=l7(Object.assign({},T,D)),X=z===A4?F:K,B={top:x.top-X.top+L.top,bottom:X.bottom-x.bottom+L.bottom,left:x.left-X.left+L.left,right:X.right-x.right+L.right},f1=c.modifiersData.offset;if(z===A4&&f1){var c1=f1[l];Object.keys(B).forEach(function(V1){var m1=[k2,E2].indexOf(V1)>=0?1:-1,M1=[p2,E2].indexOf(V1)>=0?"y":"x";B[V1]+=c1[M1]*m1})}return B}function TH(c,e){e===void 0&&(e={});var t=e,s=t.placement,l=t.boundary,n=t.rootBoundary,r=t.padding,a=t.flipVariations,i=t.allowedAutoPlacements,o=i===void 0?U7:i,u=c6(s),C=u?a?t7:t7.filter(function(p){return c6(p)===u}):f6,z=C.filter(function(p){return o.indexOf(p)>=0});z.length===0&&(z=C);var H=z.reduce(function(p,E){return p[E]=e6(c,{placement:E,boundary:l,rootBoundary:n,padding:r})[t3(E)],p},{});return Object.keys(H).sort(function(p,E){return H[p]-H[E]})}function OH(c){if(t3(c)===S5)return[];var e=Z8(c);return[Ce(c),e,Ce(e)]}function xH(c){var e=c.state,t=c.options,s=c.name;if(!e.modifiersData[s]._skip){for(var l=t.mainAxis,n=l===void 0?!0:l,r=t.altAxis,a=r===void 0?!0:r,i=t.fallbackPlacements,o=t.padding,u=t.boundary,C=t.rootBoundary,z=t.altBoundary,H=t.flipVariations,p=H===void 0?!0:H,E=t.allowedAutoPlacements,A=e.options.placement,L=t3(A),O=L===A,T=i||(O||!p?[Z8(A)]:OH(A)),_=[A].concat(T).reduce(function(U,S){return U.concat(t3(S)===S5?TH(e,{placement:S,boundary:u,rootBoundary:C,padding:o,flipVariations:p,allowedAutoPlacements:E}):S)},[]),x=e.rects.reference,K=e.rects.popper,D=new Map,F=!0,X=_[0],B=0;B<_.length;B++){var f1=_[B],c1=t3(f1),V1=c6(f1)===H4,m1=[p2,E2].indexOf(c1)>=0,M1=m1?"width":"height",z1=e6(e,{placement:f1,boundary:u,rootBoundary:C,altBoundary:z,padding:o}),n1=m1?V1?k2:L2:V1?E2:p2;x[M1]>K[M1]&&(n1=Z8(n1));var v1=Z8(n1),T1=[];if(n&&T1.push(z1[c1]<=0),a&&T1.push(z1[n1]<=0,z1[v1]<=0),T1.every(function(U){return U})){X=f1,F=!1;break}D.set(f1,T1)}if(F)for(var I1=p?3:1,A1=function(S){var Y=_.find(function(s1){var i1=D.get(s1);if(i1)return i1.slice(0,S).every(function(_1){return _1})});if(Y)return X=Y,"break"},k=I1;k>0;k--){var q=A1(k);if(q==="break")break}e.placement!==X&&(e.modifiersData[s]._skip=!0,e.placement=X,e.reset=!0)}}const Ys={name:"flip",enabled:!0,phase:"main",fn:xH,requiresIfExists:["offset"],data:{_skip:!1}};function He(c,e,t){return t===void 0&&(t={x:0,y:0}),{top:c.top-e.height-t.y,right:c.right-e.width+t.x,bottom:c.bottom-e.height+t.y,left:c.left-e.width-t.x}}function Ve(c){return[p2,k2,E2,L2].some(function(e){return c[e]>=0})}function IH(c){var e=c.state,t=c.name,s=e.rects.reference,l=e.rects.popper,n=e.modifiersData.preventOverflow,r=e6(e,{elementContext:"reference"}),a=e6(e,{altBoundary:!0}),i=He(r,s),o=He(a,l,n),u=Ve(i),C=Ve(o);e.modifiersData[t]={referenceClippingOffsets:i,popperEscapeOffsets:o,isReferenceHidden:u,hasPopperEscaped:C},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":u,"data-popper-escaped":C})}const Gs={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:IH};function $H(c,e,t){var s=t3(c),l=[L2,p2].indexOf(s)>=0?-1:1,n=typeof t=="function"?t(Object.assign({},e,{placement:c})):t,r=n[0],a=n[1];return r=r||0,a=(a||0)*l,[L2,k2].indexOf(s)>=0?{x:a,y:r}:{x:r,y:a}}function NH(c){var e=c.state,t=c.options,s=c.name,l=t.offset,n=l===void 0?[0,0]:l,r=U7.reduce(function(u,C){return u[C]=$H(C,e.rects,n),u},{}),a=r[e.placement],i=a.x,o=a.y;e.modifiersData.popperOffsets!=null&&(e.modifiersData.popperOffsets.x+=i,e.modifiersData.popperOffsets.y+=o),e.modifiersData[s]=r}const Xs={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:NH};function DH(c){var e=c.state,t=c.name;e.modifiersData[t]=Zs({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})}const J7={name:"popperOffsets",enabled:!0,phase:"read",fn:DH,data:{}};function RH(c){return c==="x"?"y":"x"}function FH(c){var e=c.state,t=c.options,s=c.name,l=t.mainAxis,n=l===void 0?!0:l,r=t.altAxis,a=r===void 0?!1:r,i=t.boundary,o=t.rootBoundary,u=t.altBoundary,C=t.padding,z=t.tether,H=z===void 0?!0:z,p=t.tetherOffset,E=p===void 0?0:p,A=e6(e,{boundary:i,rootBoundary:o,padding:C,altBoundary:u}),L=t3(e.placement),O=c6(e.placement),T=!O,_=K7(L),x=RH(_),K=e.modifiersData.popperOffsets,D=e.rects.reference,F=e.rects.popper,X=typeof E=="function"?E(Object.assign({},e.rects,{placement:e.placement})):E,B=typeof X=="number"?{mainAxis:X,altAxis:X}:Object.assign({mainAxis:0,altAxis:0},X),f1=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,c1={x:0,y:0};if(K){if(n){var V1,m1=_==="y"?p2:L2,M1=_==="y"?E2:k2,z1=_==="y"?"height":"width",n1=K[_],v1=n1+A[m1],T1=n1-A[M1],I1=H?-F[z1]/2:0,A1=O===H4?D[z1]:F[z1],k=O===H4?-F[z1]:-D[z1],q=e.elements.arrow,U=H&&q?B7(q):{width:0,height:0},S=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:Us(),Y=S[m1],s1=S[M1],i1=$6(0,D[z1],U[z1]),_1=T?D[z1]/2-I1-i1-Y-B.mainAxis:A1-i1-Y-B.mainAxis,D1=T?-D[z1]/2+I1+i1+s1+B.mainAxis:k+i1+s1+B.mainAxis,g=e.elements.arrow&&a8(e.elements.arrow),h=g?_==="y"?g.clientTop||0:g.clientLeft||0:0,V=(V1=f1==null?void 0:f1[_])!=null?V1:0,b=n1+_1-V-h,P=n1+D1-V,R=$6(H?a5(v1,b):v1,n1,H?v4(T1,P):T1);K[_]=R,c1[_]=R-n1}if(a){var G,l1=_==="x"?p2:L2,e1=_==="x"?E2:k2,t1=K[x],w=x==="y"?"height":"width",j=t1+A[l1],r1=t1-A[e1],a1=[p2,L2].indexOf(L)!==-1,p1=(G=f1==null?void 0:f1[x])!=null?G:0,y1=a1?j:t1-D[w]-F[w]-p1+B.altAxis,P1=a1?t1+D[w]+F[w]-p1-B.altAxis:r1,O1=H&&a1?HH(y1,t1,P1):$6(H?y1:j,t1,H?P1:r1);K[x]=O1,c1[x]=O1-t1}e.modifiersData[s]=c1}}const Qs={name:"preventOverflow",enabled:!0,phase:"main",fn:FH,requiresIfExists:["offset"]};function jH(c){return{scrollLeft:c.scrollLeft,scrollTop:c.scrollTop}}function UH(c){return c===$2(c)||!x2(c)?G7(c):jH(c)}function qH(c){var e=c.getBoundingClientRect(),t=Q4(e.width)/c.offsetWidth||1,s=Q4(e.height)/c.offsetHeight||1;return t!==1||s!==1}function WH(c,e,t){t===void 0&&(t=!1);var s=x2(e),l=x2(e)&&qH(e),n=Q3(e),r=J4(c,l,t),a={scrollLeft:0,scrollTop:0},i={x:0,y:0};return(s||!s&&!t)&&((n3(e)!=="body"||Q7(n))&&(a=UH(e)),x2(e)?(i=J4(e,!0),i.x+=e.clientLeft,i.y+=e.clientTop):n&&(i.x=X7(n))),{x:r.left+a.scrollLeft-i.x,y:r.top+a.scrollTop-i.y,width:r.width,height:r.height}}function BH(c){var e=new Map,t=new Set,s=[];c.forEach(function(n){e.set(n.name,n)});function l(n){t.add(n.name);var r=[].concat(n.requires||[],n.requiresIfExists||[]);r.forEach(function(a){if(!t.has(a)){var i=e.get(a);i&&l(i)}}),s.push(n)}return c.forEach(function(n){t.has(n.name)||l(n)}),s}function KH(c){var e=BH(c);return Rs.reduce(function(t,s){return t.concat(e.filter(function(l){return l.phase===s}))},[])}function ZH(c){var e;return function(){return e||(e=new Promise(function(t){Promise.resolve().then(function(){e=void 0,t(c())})})),e}}function YH(c){var e=c.reduce(function(t,s){var l=t[s.name];return t[s.name]=l?Object.assign({},l,s,{options:Object.assign({},l.options,s.options),data:Object.assign({},l.data,s.data)}):s,t},{});return Object.keys(e).map(function(t){return e[t]})}var Me={placement:"bottom",modifiers:[],strategy:"absolute"};function pe(){for(var c=arguments.length,e=new Array(c),t=0;tc(t,s,V3()||void 0,l)}function D7(c,e){const{messages:t,__i18n:s}=e,l=w1(t)?t:X1(s)?{}:{[c]:{}};if(X1(s)&&s.forEach(({locale:n,resource:r})=>{n?(l[n]=l[n]||{},r5(r,l[n])):r5(r,l)}),e.flatJson)for(const n in l)Vs(l,n)&&K0(l[n]);return l}const O8=c=>!M2(c)||X1(c);function r5(c,e){if(O8(c)||O8(e))throw m2(20);for(const t in c)Vs(c,t)&&(O8(c[t])||O8(e[t])?e[t]=c[t]:r5(c[t],e[t]))}const Zh=()=>{const c=V3();return c&&c.type[z0]?{[z0]:c.type[z0]}:null};function R7(c={}){const{__root:e}=c,t=e===void 0;let s=B1(c.inheritLocale)?c.inheritLocale:!0;const l=a2(e&&s?e.locale.value:u1(c.locale)?c.locale:"en-US"),n=a2(e&&s?e.fallbackLocale.value:u1(c.fallbackLocale)||X1(c.fallbackLocale)||w1(c.fallbackLocale)||c.fallbackLocale===!1?c.fallbackLocale:l.value),r=a2(D7(l.value,c)),a=a2(w1(c.datetimeFormats)?c.datetimeFormats:{[l.value]:{}}),i=a2(w1(c.numberFormats)?c.numberFormats:{[l.value]:{}});let o=e?e.missingWarn:B1(c.missingWarn)||Y4(c.missingWarn)?c.missingWarn:!0,u=e?e.fallbackWarn:B1(c.fallbackWarn)||Y4(c.fallbackWarn)?c.fallbackWarn:!0,C=e?e.fallbackRoot:B1(c.fallbackRoot)?c.fallbackRoot:!0,z=!!c.fallbackFormat,H=o2(c.missing)?c.missing:null,p=o2(c.missing)?oe(c.missing):null,E=o2(c.postTranslation)?c.postTranslation:null,A=B1(c.warnHtmlMessage)?c.warnHtmlMessage:!0,L=!!c.escapeParameter;const O=e?e.modifiers:w1(c.modifiers)?c.modifiers:{};let T=c.pluralRules||e&&e.pluralRules,_;function x(){return Ih({version:Bh,locale:l.value,fallbackLocale:n.value,messages:r.value,datetimeFormats:a.value,numberFormats:i.value,modifiers:O,pluralRules:T,missing:p===null?void 0:p,missingWarn:o,fallbackWarn:u,fallbackFormat:z,unresolving:!0,postTranslation:E===null?void 0:E,warnHtmlMessage:A,escapeParameter:L,__datetimeFormatters:w1(_)?_.__datetimeFormatters:void 0,__numberFormatters:w1(_)?_.__numberFormatters:void 0,__v_emitter:w1(_)?_.__v_emitter:void 0,__meta:{framework:"vue"}})}_=x(),b6(_,l.value,n.value);function K(){return[l.value,n.value,r.value,a.value,i.value]}const D=F1({get:()=>l.value,set:w=>{l.value=w,_.locale=l.value}}),F=F1({get:()=>n.value,set:w=>{n.value=w,_.fallbackLocale=n.value,b6(_,l.value,w)}}),X=F1(()=>r.value),B=F1(()=>a.value),f1=F1(()=>i.value);function c1(){return o2(E)?E:null}function V1(w){E=w,_.postTranslation=w}function m1(){return H}function M1(w){w!==null&&(p=oe(w)),H=w,_.missing=p}function z1(w,j,r1,a1,p1,y1){K();let P1;if(__INTLIFY_PROD_DEVTOOLS__)try{Qc(Zh()),P1=w(_)}finally{Qc(null)}else P1=w(_);if(e2(P1)&&P1===y5){const[O1,j1]=j();return e&&C?a1(e):p1(O1)}else{if(y1(P1))return P1;throw m2(14)}}function n1(...w){return z1(j=>se(j,...w),()=>Y0(...w),"translate",j=>j.t(...w),j=>j,j=>u1(j))}function v1(...w){const[j,r1,a1]=w;if(a1&&!M2(a1))throw m2(15);return n1(j,r1,s2({resolvedMessage:!0},a1||{}))}function T1(...w){return z1(j=>le(j,...w),()=>G0(...w),"datetime format",j=>j.d(...w),()=>Xc,j=>u1(j))}function I1(...w){return z1(j=>re(j,...w),()=>X0(...w),"number format",j=>j.n(...w),()=>Xc,j=>u1(j))}function A1(w){return w.map(j=>u1(j)?W1(q4,null,j,0):j)}const q={normalize:A1,interpolate:w=>w,type:"vnode"};function U(...w){return z1(j=>{let r1;const a1=j;try{a1.processor=q,r1=se(a1,...w)}finally{a1.processor=null}return r1},()=>Y0(...w),"translate",j=>j[Q0](...w),j=>[W1(q4,null,j,0)],j=>X1(j))}function S(...w){return z1(j=>re(j,...w),()=>X0(...w),"number format",j=>j[c7](...w),()=>[],j=>u1(j)||X1(j))}function Y(...w){return z1(j=>le(j,...w),()=>G0(...w),"datetime format",j=>j[J0](...w),()=>[],j=>u1(j)||X1(j))}function s1(w){T=w,_.pluralRules=T}function i1(w,j){const r1=u1(j)?j:l.value,a1=g(r1);return n5(a1,w)!==null}function _1(w){let j=null;const r1=n8(_,n.value,l.value);for(let a1=0;a1{s&&(l.value=w,_.locale=w,b6(_,l.value,n.value))}),d3(e.fallbackLocale,w=>{s&&(n.value=w,_.fallbackLocale=w,b6(_,l.value,n.value))})),{id:ie,locale:D,fallbackLocale:F,get inheritLocale(){return s},set inheritLocale(w){s=w,w&&e&&(l.value=e.locale.value,n.value=e.fallbackLocale.value,b6(_,l.value,n.value))},get availableLocales(){return Object.keys(r.value).sort()},messages:X,datetimeFormats:B,numberFormats:f1,get modifiers(){return O},get pluralRules(){return T||{}},get isGlobal(){return t},get missingWarn(){return o},set missingWarn(w){o=w,_.missingWarn=o},get fallbackWarn(){return u},set fallbackWarn(w){u=w,_.fallbackWarn=u},get fallbackRoot(){return C},set fallbackRoot(w){C=w},get fallbackFormat(){return z},set fallbackFormat(w){z=w,_.fallbackFormat=z},get warnHtmlMessage(){return A},set warnHtmlMessage(w){A=w,_.warnHtmlMessage=w},get escapeParameter(){return L},set escapeParameter(w){L=w,_.escapeParameter=w},t:n1,rt:v1,d:T1,n:I1,te:i1,tm:D1,getLocaleMessage:g,setLocaleMessage:h,mergeLocaleMessage:V,getDateTimeFormat:b,setDateTimeFormat:P,mergeDateTimeFormat:R,getNumberFormat:G,setNumberFormat:l1,mergeNumberFormat:e1,getPostTranslationHandler:c1,setPostTranslationHandler:V1,getMissingHandler:m1,setMissingHandler:M1,[Q0]:U,[c7]:S,[J0]:Y,[_s]:s1,[ys]:c.__injectWithOption}}function Yh(c){const e=u1(c.locale)?c.locale:"en-US",t=u1(c.fallbackLocale)||X1(c.fallbackLocale)||w1(c.fallbackLocale)||c.fallbackLocale===!1?c.fallbackLocale:e,s=o2(c.missing)?c.missing:void 0,l=B1(c.silentTranslationWarn)||Y4(c.silentTranslationWarn)?!c.silentTranslationWarn:!0,n=B1(c.silentFallbackWarn)||Y4(c.silentFallbackWarn)?!c.silentFallbackWarn:!0,r=B1(c.fallbackRoot)?c.fallbackRoot:!0,a=!!c.formatFallbackMessages,i=w1(c.modifiers)?c.modifiers:{},o=c.pluralizationRules,u=o2(c.postTranslation)?c.postTranslation:void 0,C=u1(c.warnHtmlInMessage)?c.warnHtmlInMessage!=="off":!0,z=!!c.escapeParameterHtml,H=B1(c.sync)?c.sync:!0;let p=c.messages;if(w1(c.sharedMessages)){const x=c.sharedMessages;p=Object.keys(x).reduce((D,F)=>{const X=D[F]||(D[F]={});return s2(X,x[F]),D},p||{})}const{__i18n:E,__root:A,__injectWithOption:L}=c,O=c.datetimeFormats,T=c.numberFormats,_=c.flatJson;return{locale:e,fallbackLocale:t,messages:p,flatJson:_,datetimeFormats:O,numberFormats:T,missing:s,missingWarn:l,fallbackWarn:n,fallbackRoot:r,fallbackFormat:a,modifiers:i,pluralRules:o,postTranslation:u,warnHtmlMessage:C,escapeParameter:z,inheritLocale:H,__i18n:E,__root:A,__injectWithOption:L}}function e7(c={}){const e=R7(Yh(c)),t={id:e.id,get locale(){return e.locale.value},set locale(s){e.locale.value=s},get fallbackLocale(){return e.fallbackLocale.value},set fallbackLocale(s){e.fallbackLocale.value=s},get messages(){return e.messages.value},get datetimeFormats(){return e.datetimeFormats.value},get numberFormats(){return e.numberFormats.value},get availableLocales(){return e.availableLocales},get formatter(){return{interpolate(){return[]}}},set formatter(s){},get missing(){return e.getMissingHandler()},set missing(s){e.setMissingHandler(s)},get silentTranslationWarn(){return B1(e.missingWarn)?!e.missingWarn:e.missingWarn},set silentTranslationWarn(s){e.missingWarn=B1(s)?!s:s},get silentFallbackWarn(){return B1(e.fallbackWarn)?!e.fallbackWarn:e.fallbackWarn},set silentFallbackWarn(s){e.fallbackWarn=B1(s)?!s:s},get modifiers(){return e.modifiers},get formatFallbackMessages(){return e.fallbackFormat},set formatFallbackMessages(s){e.fallbackFormat=s},get postTranslation(){return e.getPostTranslationHandler()},set postTranslation(s){e.setPostTranslationHandler(s)},get sync(){return e.inheritLocale},set sync(s){e.inheritLocale=s},get warnHtmlInMessage(){return e.warnHtmlMessage?"warn":"off"},set warnHtmlInMessage(s){e.warnHtmlMessage=s!=="off"},get escapeParameterHtml(){return e.escapeParameter},set escapeParameterHtml(s){e.escapeParameter=s},get preserveDirectiveContent(){return!0},set preserveDirectiveContent(s){},get pluralizationRules(){return e.pluralRules||{}},__composer:e,t(...s){const[l,n,r]=s,a={};let i=null,o=null;if(!u1(l))throw m2(15);const u=l;return u1(n)?a.locale=n:X1(n)?i=n:w1(n)&&(o=n),X1(r)?i=r:w1(r)&&(o=r),e.t(u,i||o||{},a)},rt(...s){return e.rt(...s)},tc(...s){const[l,n,r]=s,a={plural:1};let i=null,o=null;if(!u1(l))throw m2(15);const u=l;return u1(n)?a.locale=n:e2(n)?a.plural=n:X1(n)?i=n:w1(n)&&(o=n),u1(r)?a.locale=r:X1(r)?i=r:w1(r)&&(o=r),e.t(u,i||o||{},a)},te(s,l){return e.te(s,l)},tm(s){return e.tm(s)},getLocaleMessage(s){return e.getLocaleMessage(s)},setLocaleMessage(s,l){e.setLocaleMessage(s,l)},mergeLocaleMessage(s,l){e.mergeLocaleMessage(s,l)},d(...s){return e.d(...s)},getDateTimeFormat(s){return e.getDateTimeFormat(s)},setDateTimeFormat(s,l){e.setDateTimeFormat(s,l)},mergeDateTimeFormat(s,l){e.mergeDateTimeFormat(s,l)},n(...s){return e.n(...s)},getNumberFormat(s){return e.getNumberFormat(s)},setNumberFormat(s,l){e.setNumberFormat(s,l)},mergeNumberFormat(s,l){e.mergeNumberFormat(s,l)},getChoiceIndex(s,l){return-1},__onComponentInstanceCreated(s){const{componentInstanceCreatedListener:l}=c;l&&l(s,t)}};return t}const F7={tag:{type:[String,Object]},locale:{type:String},scope:{type:String,validator:c=>c==="parent"||c==="global",default:"parent"},i18n:{type:Object}},fe={name:"i18n-t",props:s2({keypath:{type:String,required:!0},plural:{type:[Number,String],validator:c=>e2(c)||!isNaN(c)}},F7),setup(c,e){const{slots:t,attrs:s}=e,l=c.i18n||r8({useScope:c.scope,__useComponent:!0}),n=Object.keys(t).filter(r=>r!=="_");return()=>{const r={};c.locale&&(r.locale=c.locale),c.plural!==void 0&&(r.plural=u1(c.plural)?+c.plural:c.plural);const a=Gh(e,n),i=l[Q0](c.keypath,a,r),o=s2({},s);return u1(c.tag)||M2(c.tag)?W3(c.tag,o,i):W3(Y1,o,i)}}};function Gh({slots:c},e){return e.length===1&&e[0]==="default"?c.default?c.default():[]:e.reduce((t,s)=>{const l=c[s];return l&&(t[s]=l()),t},{})}function Ss(c,e,t,s){const{slots:l,attrs:n}=e;return()=>{const r={part:!0};let a={};c.locale&&(r.locale=c.locale),u1(c.format)?r.key=c.format:M2(c.format)&&(u1(c.format.key)&&(r.key=c.format.key),a=Object.keys(c.format).reduce((C,z)=>t.includes(z)?s2({},C,{[z]:c.format[z]}):C,{}));const i=s(c.value,r,a);let o=[r.key];X1(i)?o=i.map((C,z)=>{const H=l[C.type];return H?H({[C.type]:C.value,index:z,parts:i}):[C.value]}):u1(i)&&(o=[i]);const u=s2({},n);return u1(c.tag)||M2(c.tag)?W3(c.tag,u,o):W3(Y1,u,o)}}const Xh=["localeMatcher","style","unit","unitDisplay","currency","currencyDisplay","useGrouping","numberingSystem","minimumIntegerDigits","minimumFractionDigits","maximumFractionDigits","minimumSignificantDigits","maximumSignificantDigits","notation","formatMatcher"],ue={name:"i18n-n",props:s2({value:{type:Number,required:!0},format:{type:[String,Object]}},F7),setup(c,e){const t=c.i18n||r8({useScope:"parent",__useComponent:!0});return Ss(c,e,Xh,(...s)=>t[c7](...s))}},Qh=["dateStyle","timeStyle","fractionalSecondDigits","calendar","dayPeriod","numberingSystem","localeMatcher","timeZone","hour12","hourCycle","formatMatcher","weekday","era","year","month","day","hour","minute","second","timeZoneName"],he={name:"i18n-d",props:s2({value:{type:[Number,Date],required:!0},format:{type:[String,Object]}},F7),setup(c,e){const t=c.i18n||r8({useScope:"parent",__useComponent:!0});return Ss(c,e,Qh,(...s)=>t[J0](...s))}};function Jh(c,e){const t=c;if(c.mode==="composition")return t.__getInstance(e)||c.global;{const s=t.__getInstance(e);return s!=null?s.__composer:c.global.__composer}}function cm(c){const e=(t,{instance:s,value:l,modifiers:n})=>{if(!s||!s.$)throw m2(22);const r=Jh(c,s.$),a=em(l);t.textContent=r.t(...tm(a))};return{beforeMount:e,beforeUpdate:e}}function em(c){if(u1(c))return{path:c};if(w1(c)){if(!("path"in c))throw m2(19,"path");return c}else throw m2(20)}function tm(c){const{path:e,locale:t,args:s,choice:l,plural:n}=c,r={},a=s||{};return u1(t)&&(r.locale=t),e2(l)&&(r.plural=l),e2(n)&&(r.plural=n),[e,a,r]}function sm(c,e,...t){const s=w1(t[0])?t[0]:{},l=!!s.useI18nComponentName;(B1(s.globalInstall)?s.globalInstall:!0)&&(c.component(l?"i18n":fe.name,fe),c.component(ue.name,ue),c.component(he.name,he)),c.directive("t",cm(e))}function lm(c,e,t){return{beforeCreate(){const s=V3();if(!s)throw m2(22);const l=this.$options;if(l.i18n){const n=l.i18n;l.__i18n&&(n.__i18n=l.__i18n),n.__root=e,this===this.$root?this.$i18n=me(c,n):(n.__injectWithOption=!0,this.$i18n=e7(n))}else l.__i18n?this===this.$root?this.$i18n=me(c,l):this.$i18n=e7({__i18n:l.__i18n,__injectWithOption:!0,__root:e}):this.$i18n=c;c.__onComponentInstanceCreated(this.$i18n),t.__setInstance(s,this.$i18n),this.$t=(...n)=>this.$i18n.t(...n),this.$rt=(...n)=>this.$i18n.rt(...n),this.$tc=(...n)=>this.$i18n.tc(...n),this.$te=(n,r)=>this.$i18n.te(n,r),this.$d=(...n)=>this.$i18n.d(...n),this.$n=(...n)=>this.$i18n.n(...n),this.$tm=n=>this.$i18n.tm(n)},mounted(){},beforeUnmount(){const s=V3();if(!s)throw m2(22);delete this.$t,delete this.$rt,delete this.$tc,delete this.$te,delete this.$d,delete this.$n,delete this.$tm,t.__deleteInstance(s),delete this.$i18n}}}function me(c,e){c.locale=e.locale||c.locale,c.fallbackLocale=e.fallbackLocale||c.fallbackLocale,c.missing=e.missing||c.missing,c.silentTranslationWarn=e.silentTranslationWarn||c.silentFallbackWarn,c.silentFallbackWarn=e.silentFallbackWarn||c.silentFallbackWarn,c.formatFallbackMessages=e.formatFallbackMessages||c.formatFallbackMessages,c.postTranslation=e.postTranslation||c.postTranslation,c.warnHtmlInMessage=e.warnHtmlInMessage||c.warnHtmlInMessage,c.escapeParameterHtml=e.escapeParameterHtml||c.escapeParameterHtml,c.sync=e.sync||c.sync,c.__composer[_s](e.pluralizationRules||c.pluralizationRules);const t=D7(c.locale,{messages:e.messages,__i18n:e.__i18n});return Object.keys(t).forEach(s=>c.mergeLocaleMessage(s,t[s])),e.datetimeFormats&&Object.keys(e.datetimeFormats).forEach(s=>c.mergeDateTimeFormat(s,e.datetimeFormats[s])),e.numberFormats&&Object.keys(e.numberFormats).forEach(s=>c.mergeNumberFormat(s,e.numberFormats[s])),c}function nm(c={}){const e=__VUE_I18N_LEGACY_API__&&B1(c.legacy)?c.legacy:__VUE_I18N_LEGACY_API__,t=!!c.globalInjection,s=new Map,l=__VUE_I18N_LEGACY_API__&&e?e7(c):R7(c),n=g3(""),r={get mode(){return __VUE_I18N_LEGACY_API__&&e?"legacy":"composition"},async install(a,...i){a.__VUE_I18N_SYMBOL__=n,a.provide(a.__VUE_I18N_SYMBOL__,r),!e&&t&&fm(a,r.global),__VUE_I18N_FULL_INSTALL__&&sm(a,r,...i),__VUE_I18N_LEGACY_API__&&e&&a.mixin(lm(l,l.__composer,r))},get global(){return l},__instances:s,__getInstance(a){return s.get(a)||null},__setInstance(a,i){s.set(a,i)},__deleteInstance(a){s.delete(a)}};return r}function r8(c={}){const e=V3();if(e==null)throw m2(16);if(!e.appContext.app.__VUE_I18N_SYMBOL__)throw m2(17);const t=q2(e.appContext.app.__VUE_I18N_SYMBOL__);if(!t)throw m2(22);const s=t.mode==="composition"?t.global:t.global.__composer,l=b5(c)?"__i18n"in e.type?"local":"global":c.useScope?c.useScope:"local";if(l==="global"){let a=M2(c.messages)?c.messages:{};"__i18nGlobal"in e.type&&(a=D7(s.locale.value,{messages:a,__i18n:e.type.__i18nGlobal}));const i=Object.keys(a);if(i.length&&i.forEach(o=>{s.mergeLocaleMessage(o,a[o])}),M2(c.datetimeFormats)){const o=Object.keys(c.datetimeFormats);o.length&&o.forEach(u=>{s.mergeDateTimeFormat(u,c.datetimeFormats[u])})}if(M2(c.numberFormats)){const o=Object.keys(c.numberFormats);o.length&&o.forEach(u=>{s.mergeNumberFormat(u,c.numberFormats[u])})}return s}if(l==="parent"){let a=rm(t,e,c.__useComponent);return a==null&&(a=s),a}if(t.mode==="legacy")throw m2(18);const n=t;let r=n.__getInstance(e);if(r==null){const a=e.type,i=s2({},c);a.__i18n&&(i.__i18n=a.__i18n),s&&(i.__root=s),r=R7(i),am(n,e),n.__setInstance(e,r)}return r}function rm(c,e,t=!1){let s=null;const l=e.root;let n=e.parent;for(;n!=null;){const r=c;if(c.mode==="composition")s=r.__getInstance(n);else{const a=r.__getInstance(n);a!=null&&(s=a.__composer),t&&s&&!s[ys]&&(s=null)}if(s!=null||l===n)break;n=n.parent}return s}function am(c,e,t){s8(()=>{},e),_7(()=>{c.__deleteInstance(e)},e)}const im=["locale","fallbackLocale","availableLocales"],om=["t","rt","d","n","tm"];function fm(c,e){const t=Object.create(null);im.forEach(s=>{const l=Object.getOwnPropertyDescriptor(e,s);if(!l)throw m2(22);const n=G1(l.value)?{get(){return l.value.value},set(r){l.value.value=r}}:{get(){return l.get&&l.get()}};Object.defineProperty(t,s,n)}),c.config.globalProperties.$i18n=t,om.forEach(s=>{const l=Object.getOwnPropertyDescriptor(e,s);if(!l||!l.value)throw m2(22);Object.defineProperty(c.config.globalProperties,`$${s}`,l)})}Oh(Rh);Kh();if(__INTLIFY_PROD_DEVTOOLS__){const c=I6();c.__INTLIFY__=!0,wh(c.__INTLIFY_DEVTOOLS_GLOBAL_HOOK__)}const um=f("legend",{class:"mt-4"},"General",-1),hm={class:"form-group"},mm={class:"form-label mt-4"},dm={class:"form-group"},zm={class:"form-label mt-4"},Cm=f("legend",{class:"mt-4"},"Cryptography",-1),vm={key:0,class:"form-group"},Hm={class:"form-label mt-4"},Vm={class:"form-group"},Mm={class:"form-label mt-4"},pm={class:"form-group"},Lm={class:"form-label mt-4"},gm=f("legend",{class:"mt-4"},"Networking",-1),bm={key:0,class:"form-group"},_m={class:"form-label mt-4"},ym={class:"form-group"},Sm={class:"form-label mt-4"},wm={class:"form-group"},Em={class:"form-label mt-4"},km={class:"form-group"},Am={class:"form-label mt-4"},Pm={class:"form-group"},Tm={class:"form-label mt-4"},Om={class:"row"},xm={class:"form-group col-md-6"},Im={class:"form-label mt-4"},$m={class:"form-group col-md-6"},Nm={class:"form-label mt-4"},Dm=f("legend",{class:"mt-4"},"State",-1),Rm={class:"form-check form-switch"},Fm=f("label",{class:"form-check-label"},"Disabled",-1),jm={class:"form-check form-switch"},Um=f("label",{class:"form-check-label"},"Ignore global settings",-1),qm=f("div",{class:"flex-fill text-start"},[f("button",{type:"button",class:"btn btn-danger me-1"},"Delete")],-1),Wm=f("button",{type:"button",class:"btn btn-primary me-1"},"Save",-1),Bm=["onClick"],Km={__name:"PeerEditModal",props:{peerId:String,visible:Boolean},emits:["close"],setup(c,{emit:e}){const t=c,{t:s}=r8(),l=x7(),n=l8(),r=F1(()=>l.Find(t.peerId)),a=F1(()=>{let H=n.GetSelected;return H||(H={Identifier:"none",Mode:"server"}),H}),i=F1(()=>t.visible?a.value.Mode==="server"?r.value?s("interfaces.peer.edit")+": "+r.value.Name:s("interfaces.peer.new"):r.value?s("interfaces.endpoint.edit")+": "+r.value.Name:s("interfaces.endpoint.new"):""),o=a2(u());a2({title:"",content:"",cause:"",type:"normal"});function u(){return{Disabled:!1,IgnoreGlobalSettings:!0,Endpoint:{Value:"",Overridable:!1},AllowedIPsStr:{Value:"",Overridable:!1},ExtraAllowedIPsStr:"",PrivateKey:"",PublicKey:"",PresharedKey:"",PersistentKeepalive:{Value:0,Overridable:!1},DisplayName:"",Identifier:"",UserIdentifier:"",InterfaceConfig:{PublicKey:{Value:"",Overridable:!1},AddressStr:{Value:"",Overridable:!1},DnsStr:{Value:"",Overridable:!1},DnsSearchStr:{Value:"",Overridable:!1},Mtu:{Value:0,Overridable:!1},FirewallMark:{Value:0,Overridable:!1},RoutingTable:{Value:"",Overridable:!1},PreUp:{Value:"",Overridable:!1},PostUp:{Value:"",Overridable:!1},PreDown:{Value:"",Overridable:!1},PostDown:{Value:"",Overridable:!1}}}}d3(()=>t.visible,async(H,p)=>{p===!1&&H===!0&&(r.value||await C())});async function C(){console.log("loading new peer data..."),t2({title:"Authorization",text:"You have been logged in!"}),t2({title:"Authorization2",text:"You have been logged in!"}),t2({title:"Authorization3",text:"You have been logged in!"})}function z(){o.value=u(),e("close")}return(H,p)=>(C1(),L3(O7,{title:Z(i),visible:c.visible,onClose:z},{default:V2(()=>[f("fieldset",null,[um,f("div",hm,[f("label",mm,$(H.$t("modals.peeredit.displayname")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"A descriptive name of the peer","onUpdate:modelValue":p[0]||(p[0]=E=>o.value.DisplayName=E)},null,512),[[S1,o.value.DisplayName]])]),f("div",dm,[f("label",zm,$(H.$t("modals.peeredit.linkeduser")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Linked user","onUpdate:modelValue":p[1]||(p[1]=E=>o.value.UserIdentifier=E)},null,512),[[S1,o.value.UserIdentifier]])])]),f("fieldset",null,[Cm,Z(a).Mode==="server"?(C1(),b1("div",vm,[f("label",Hm,$(H.$t("modals.peeredit.privatekey")),1),g1(f("input",{type:"email",class:"form-control",placeholder:"The private key",required:"","onUpdate:modelValue":p[2]||(p[2]=E=>o.value.PrivateKey=E)},null,512),[[S1,o.value.PrivateKey]])])):R1("",!0),f("div",Vm,[f("label",Mm,$(H.$t("modals.peeredit.publickey")),1),g1(f("input",{type:"email",class:"form-control",placeholder:"The public key",required:"","onUpdate:modelValue":p[3]||(p[3]=E=>o.value.PublicKey=E)},null,512),[[S1,o.value.PublicKey]])]),f("div",pm,[f("label",Lm,$(H.$t("modals.peeredit.presharedkey")),1),g1(f("input",{type:"email",class:"form-control",placeholder:"Optional pre-shared key","onUpdate:modelValue":p[4]||(p[4]=E=>o.value.PresharedKey=E)},null,512),[[S1,o.value.PresharedKey]])])]),f("fieldset",null,[gm,Z(a).Mode==="client"?(C1(),b1("div",bm,[f("label",_m,$(H.$t("modals.peeredit.endpoint")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Endpoint Address","onUpdate:modelValue":p[5]||(p[5]=E=>o.value.Endpoint.Value=E)},null,512),[[S1,o.value.Endpoint.Value]])])):R1("",!0),f("div",ym,[f("label",Sm,$(H.$t("modals.peeredit.ips")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Client IP Address","onUpdate:modelValue":p[6]||(p[6]=E=>o.value.InterfaceConfig.AddressStr.Value=E)},null,512),[[S1,o.value.InterfaceConfig.AddressStr.Value]])]),f("div",wm,[f("label",Em,$(H.$t("modals.peeredit.allowedips")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Allowed IP Address","onUpdate:modelValue":p[7]||(p[7]=E=>o.value.AllowedIPsStr.Value=E)},null,512),[[S1,o.value.AllowedIPsStr.Value]])]),f("div",km,[f("label",Am,$(H.$t("modals.peeredit.extraallowedips")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Extra Allowed IP's (Server Sided)","onUpdate:modelValue":p[8]||(p[8]=E=>o.value.ExtraAllowedIPsStr.Value=E)},null,512),[[S1,o.value.ExtraAllowedIPsStr.Value]])]),f("div",Pm,[f("label",Tm,$(H.$t("modals.peeredit.dns")),1),g1(f("input",{type:"text",class:"form-control",placeholder:"Client DNS Servers","onUpdate:modelValue":p[9]||(p[9]=E=>o.value.InterfaceConfig.DnsStr.Value=E)},null,512),[[S1,o.value.InterfaceConfig.DnsStr.Value]])]),f("div",Om,[f("div",xm,[f("label",Im,$(H.$t("modals.peeredit.persistendkeepalive")),1),g1(f("input",{type:"number",class:"form-control",placeholder:"Persistent Keepalive (0 = off)","onUpdate:modelValue":p[10]||(p[10]=E=>o.value.PersistentKeepalive.Value=E)},null,512),[[S1,o.value.PersistentKeepalive.Value]])]),f("div",$m,[f("label",Nm,$(H.$t("modals.peeredit.mtu")),1),g1(f("input",{type:"number",class:"form-control",placeholder:"Client MTU (0 = default)","onUpdate:modelValue":p[11]||(p[11]=E=>o.value.InterfaceConfig.Mtu.Value=E)},null,512),[[S1,o.value.InterfaceConfig.Mtu.Value]])])])]),f("fieldset",null,[Dm,f("div",Rm,[g1(f("input",{class:"form-check-input",type:"checkbox","onUpdate:modelValue":p[12]||(p[12]=E=>o.value.Disabled=E)},null,512),[[t5,o.value.Disabled]]),Fm]),f("div",jm,[g1(f("input",{class:"form-check-input",type:"checkbox",checked:"","onUpdate:modelValue":p[13]||(p[13]=E=>o.value.IgnoreGlobalSettings=E)},null,512),[[t5,o.value.IgnoreGlobalSettings]]),Um])])]),footer:V2(()=>[qm,Wm,f("button",{onClick:i2(z,["prevent"]),type:"button",class:"btn btn-secondary"},"Discard",8,Bm)]),_:1},8,["title","visible"]))}};const Zm={class:"nav nav-tabs"},Ym=f("li",{class:"nav-item"},[f("a",{class:"nav-link active","data-bs-toggle":"tab",href:"#interface"},"Interface")],-1),Gm={key:0,class:"nav-item"},Xm=f("a",{class:"nav-link","data-bs-toggle":"tab",href:"#peerdefaults"},"Peer Defaults",-1),Qm=[Xm],Jm={id:"interfaceTabs",class:"tab-content"},cd={id:"interface",class:"tab-pane fade active show"},ed=f("legend",{class:"mt-4"},"General",-1),td={key:0,class:"form-group"},sd={class:"form-label mt-4"},ld={class:"form-group"},nd={class:"form-label mt-4"},rd=f("option",{value:"server"},"Server Mode",-1),ad=f("option",{value:"client"},"Client Mode",-1),id=f("option",{value:"any"},"Custom Mode",-1),od=[rd,ad,id],fd={class:"form-group"},ud={class:"form-label mt-4"},hd=f("legend",{class:"mt-4"},"Cryptography",-1),md={class:"form-group"},dd={class:"form-label mt-4"},zd={class:"form-group"},Cd={class:"form-label mt-4"},vd=f("legend",{class:"mt-4"},"Networking",-1),Hd={class:"form-group"},Vd={class:"form-label mt-4"},Md={key:0,class:"form-group"},pd={class:"form-label mt-4"},Ld={class:"form-group"},gd={class:"form-label mt-4"},bd={class:"form-group"},_d={class:"form-label mt-4"},yd={class:"row"},Sd={class:"form-group col-md-6"},wd={class:"form-label mt-4"},Ed={class:"form-group col-md-6"},kd={class:"form-label mt-4"},Ad={class:"row"},Pd={class:"form-group col-md-6"},Td={class:"form-label mt-4"},Od=f("div",{class:"form-group col-md-6"},null,-1),xd=f("legend",{class:"mt-4"},"Hooks",-1),Id={class:"form-group"},$d={class:"form-label mt-4"},Nd={class:"form-group"},Dd={class:"form-label mt-4"},Rd={class:"form-group"},Fd={class:"form-label mt-4"},jd={class:"form-group"},Ud={class:"form-label mt-4"},qd=f("legend",{class:"mt-4"},"State",-1),Wd={class:"form-check form-switch"},Bd=f("label",{class:"form-check-label"},"Disabled",-1),Kd={class:"form-check form-switch"},Zd=f("label",{class:"form-check-label"},"Save Config to File",-1),Yd={id:"peerdefaults",class:"tab-pane fade"},Gd=f("legend",{class:"mt-4"},"Networking",-1),Xd={class:"form-group"},Qd={class:"form-label mt-4"},Jd=f("small",{class:"form-text text-muted"},"Peers will get IP addresses from those subnets.",-1),cz={class:"form-group"},ez={class:"form-label mt-4"},tz=f("small",{class:"form-text text-muted"},"Peers will get IP addresses from those subnets.",-1),sz={class:"form-group"},lz={class:"form-label mt-4"},nz={class:"form-group"},rz={class:"form-label mt-4"},az={class:"form-group"},iz={class:"form-label mt-4"},oz={class:"row"},fz={class:"form-group col-md-6"},uz={class:"form-label mt-4"},hz={class:"form-group col-md-6"},mz={class:"form-label mt-4"},dz={class:"row"},zz={class:"form-group col-md-6"},Cz={class:"form-label mt-4"},vz={class:"form-group col-md-6"},Hz={class:"form-label mt-4"},Vz=f("legend",{class:"mt-4"},"Hooks",-1),Mz={class:"form-group"},pz={class:"form-label mt-4"},Lz={class:"form-group"},gz={class:"form-label mt-4"},bz={class:"form-group"},_z={class:"form-label mt-4"},yz={class:"form-group"},Sz={class:"form-label mt-4"},wz={class:"flex-fill text-start"},Ez=["onClick"],kz=["onClick"],Az=["onClick"],Pz={__name:"InterfaceEditModal",props:{interfaceId:String,visible:Boolean},emits:["close"],setup(c,{emit:e}){const t=c,{t:s}=r8(),l=l8(),n=F1(()=>l.Find(t.interfaceId)),r=F1(()=>t.visible?n.value?s("interfaces.interface.edit")+": "+n.value.Identifier:s("interfaces.interface.new"):""),a=a2(i());function i(){return{Disabled:!1,DisplayName:"",Identifier:"",Mode:"server",PublicKey:"",PrivateKey:"",ListenPort:51820,AddressStr:"",DnsStr:"",DnsSearchStr:"",Mtu:0,FirewallMark:0,RoutingTable:"",PreUp:"",PostUp:"",PreDown:"",PostDown:"",SaveConfig:!1,PeerDefNetworkStr:"",PeerDefDnsStr:"",PeerDefDnsSearchStr:"",PeerDefEndpoint:"",PeerDefAllowedIPsStr:"",PeerDefMtu:0,PeerDefPersistentKeepalive:0,PeerDefFirewallMark:0,PeerDefRoutingTable:"",PeerDefPreUp:"",PeerDefPostUp:"",PeerDefPreDown:"",PeerDefPostDown:""}}d3(()=>t.visible,async(z,H)=>{H===!1&&z===!0&&(console.log(n.value),n.value?(a.value.Disabled=n.value.Disabled,a.value.Identifier=n.value.Identifier,a.value.DisplayName=n.value.DisplayName,a.value.Mode=n.value.Mode,a.value.PublicKey=n.value.PublicKey,a.value.PrivateKey=n.value.PrivateKey,a.value.ListenPort=n.value.ListenPort,a.value.AddressStr=n.value.AddressStr,a.value.DnsStr=n.value.DnsStr,a.value.DnsSearchStr=n.value.DnsSearchStr,a.value.Mtu=n.value.Mtu,a.value.FirewallMark=n.value.FirewallMark,a.value.RoutingTable=n.value.RoutingTable,a.value.PreUp=n.value.PreUp,a.value.PostUp=n.value.PostUp,a.value.PreDown=n.value.PreDown,a.value.PostDown=n.value.PostDown,a.value.SaveConfig=n.value.SaveConfig,a.value.PeerDefNetworkStr=n.value.PeerDefNetworkStr,a.value.PeerDefDnsStr=n.value.PeerDefDnsStr,a.value.PeerDefDnsSearchStr=n.value.PeerDefDnsSearchStr,a.value.PeerDefEndpoint=n.value.PeerDefEndpoint,a.value.PeerDefAllowedIPsStr=n.value.PeerDefAllowedIPsStr,a.value.PeerDefMtu=n.value.PeerDefMtu,a.value.PeerDefPersistentKeepalive=n.value.PeerDefPersistentKeepalive,a.value.PeerDefFirewallMark=n.value.PeerDefFirewallMark,a.value.PeerDefRoutingTable=n.value.PeerDefRoutingTable,a.value.PeerDefPreUp=n.value.PeerDefPreUp,a.value.PeerDefPostUp=n.value.PeerDefPostUp,a.value.PeerDefPreDown=n.value.PeerDefPreDown,a.value.PeerDefPostDown=n.value.PeerDefPostDown):(await l.PrepareInterface(),a.value.Identifier=l.Prepared.Identifier,a.value.DisplayName=l.Prepared.DisplayName,a.value.Mode=l.Prepared.Mode,a.value.PublicKey=l.Prepared.PublicKey,a.value.PrivateKey=l.Prepared.PrivateKey,a.value.ListenPort=l.Prepared.ListenPort,a.value.AddressStr=l.Prepared.AddressStr,a.value.DnsStr=l.Prepared.DnsStr,a.value.DnsSearchStr=l.Prepared.DnsSearchStr,a.value.Mtu=l.Prepared.Mtu,a.value.FirewallMark=l.Prepared.FirewallMark,a.value.RoutingTable=l.Prepared.RoutingTable,a.value.PreUp=l.Prepared.PreUp,a.value.PostUp=l.Prepared.PostUp,a.value.PreDown=l.Prepared.PreDown,a.value.PostDown=l.Prepared.PostDown,a.value.SaveConfig=l.Prepared.SaveConfig,a.value.PeerDefNetworkStr=l.Prepared.PeerDefNetworkStr,a.value.PeerDefDnsStr=l.Prepared.PeerDefDnsStr,a.value.PeerDefDnsSearchStr=l.Prepared.PeerDefDnsSearchStr,a.value.PeerDefEndpoint=l.Prepared.PeerDefEndpoint,a.value.PeerDefAllowedIPsStr=l.Prepared.PeerDefAllowedIPsStr,a.value.PeerDefMtu=n.value.PeerDefMtu,a.value.PeerDefPersistentKeepalive=l.Prepared.PeerDefPersistentKeepalive,a.value.PeerDefFirewallMark=l.Prepared.PeerDefFirewallMark,a.value.PeerDefRoutingTable=l.Prepared.PeerDefRoutingTable,a.value.PeerDefPreUp=l.Prepared.PeerDefPreUp,a.value.PeerDefPostUp=l.Prepared.PeerDefPostUp,a.value.PeerDefPreDown=l.Prepared.PeerDefPreDown,a.value.PeerDefPostDown=l.Prepared.PeerDefPostDown))});function o(){a.value=i(),e("close")}async function u(){try{t.interfaceId!=="#NEW#"?await l.UpdateInterface(n.value.Identifier,a.value):await l.CreateInterface(a.value),o()}catch{t2({title:"Backend Connection Failure",text:"Failed to save interface!",type:"error"})}}async function C(){try{await l.DeleteInterface(n.value.Identifier),o()}catch{t2({title:"Backend Connection Failure",text:"Failed to delete interface!",type:"error"})}}return(z,H)=>(C1(),L3(O7,{title:Z(r),visible:c.visible,onClose:o},{default:V2(()=>[f("ul",Zm,[Ym,a.value.Mode==="server"?(C1(),b1("li",Gm,Qm)):R1("",!0)]),f("div",Jm,[f("div",cd,[f("fieldset",null,[ed,t.interfaceId==="#NEW#"?(C1(),b1("div",td,[f("label",sd,$(z.$t("modals.interfaceedit.identifier")),1),g1(f("input",{"onUpdate:modelValue":H[0]||(H[0]=p=>a.value.Identifier=p),class:"form-control",placeholder:"The device identifier",type:"text"},null,512),[[S1,a.value.Identifier]])])):R1("",!0),f("div",ld,[f("label",nd,$(z.$t("modals.interfaceedit.displayname")),1),g1(f("select",{"onUpdate:modelValue":H[1]||(H[1]=p=>a.value.Mode=p),class:"form-select"},od,512),[[F0,a.value.Mode]])]),f("div",fd,[f("label",ud,$(z.$t("modals.interfaceedit.displayname")),1),g1(f("input",{"onUpdate:modelValue":H[2]||(H[2]=p=>a.value.DisplayName=p),class:"form-control",placeholder:"A descriptive name of the interface",type:"text"},null,512),[[S1,a.value.DisplayName]])])]),f("fieldset",null,[hd,f("div",md,[f("label",dd,$(z.$t("modals.interfaceedit.privatekey")),1),g1(f("input",{"onUpdate:modelValue":H[3]||(H[3]=p=>a.value.PrivateKey=p),class:"form-control",placeholder:"The private key",required:"",type:"email"},null,512),[[S1,a.value.PrivateKey]])]),f("div",zd,[f("label",Cd,$(z.$t("modals.interfaceedit.publickey")),1),g1(f("input",{"onUpdate:modelValue":H[4]||(H[4]=p=>a.value.PublicKey=p),class:"form-control",placeholder:"The public key",required:"",type:"email"},null,512),[[S1,a.value.PublicKey]])])]),f("fieldset",null,[vd,f("div",Hd,[f("label",Vd,$(z.$t("modals.interfaceedit.ips")),1),g1(f("input",{"onUpdate:modelValue":H[5]||(H[5]=p=>a.value.AddressStr=p),class:"form-control",placeholder:"IP Address",type:"text"},null,512),[[S1,a.value.AddressStr]])]),a.value.Type==="server"?(C1(),b1("div",Md,[f("label",pd,$(z.$t("modals.interfaceedit.listenport")),1),g1(f("input",{"onUpdate:modelValue":H[6]||(H[6]=p=>a.value.ListenPort=p),class:"form-control",placeholder:"Listen Port",type:"text"},null,512),[[S1,a.value.ListenPort]])])):R1("",!0),f("div",Ld,[f("label",gd,$(z.$t("modals.interfaceedit.dns")),1),g1(f("input",{"onUpdate:modelValue":H[7]||(H[7]=p=>a.value.DnsStr=p),class:"form-control",placeholder:"DNS Servers",type:"text"},null,512),[[S1,a.value.DnsStr]])]),f("div",bd,[f("label",_d,$(z.$t("modals.interfaceedit.dnssearch")),1),g1(f("input",{"onUpdate:modelValue":H[8]||(H[8]=p=>a.value.DnsSearchStr=p),class:"form-control",placeholder:"DNS Search prefix",type:"text"},null,512),[[S1,a.value.DnsSearchStr]])]),f("div",yd,[f("div",Sd,[f("label",wd,$(z.$t("modals.interfaceedit.mtu")),1),g1(f("input",{"onUpdate:modelValue":H[9]||(H[9]=p=>a.value.Mtu=p),class:"form-control",placeholder:"Client MTU (0 = default)",type:"number"},null,512),[[S1,a.value.Mtu]])]),f("div",Ed,[f("label",kd,$(z.$t("modals.interfaceedit.firewallmark")),1),g1(f("input",{"onUpdate:modelValue":H[10]||(H[10]=p=>a.value.FirewallMark=p),class:"form-control",placeholder:"Firewall Mark (0 = default)",type:"number"},null,512),[[S1,a.value.FirewallMark]])])]),f("div",Ad,[f("div",Pd,[f("label",Td,$(z.$t("modals.interfaceedit.routingtable")),1),g1(f("input",{"onUpdate:modelValue":H[11]||(H[11]=p=>a.value.RoutingTable=p),class:"form-control",placeholder:"Routing Table (0 = default)",type:"number"},null,512),[[S1,a.value.RoutingTable]])]),Od])]),f("fieldset",null,[xd,f("div",Id,[f("label",$d,$(z.$t("modals.interfaceedit.preup")),1),g1(f("textarea",{"onUpdate:modelValue":H[12]||(H[12]=p=>a.value.PreUp=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PreUp]])]),f("div",Nd,[f("label",Dd,$(z.$t("modals.interfaceedit.postup")),1),g1(f("textarea",{"onUpdate:modelValue":H[13]||(H[13]=p=>a.value.PostUp=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PostUp]])]),f("div",Rd,[f("label",Fd,$(z.$t("modals.interfaceedit.predown")),1),g1(f("textarea",{"onUpdate:modelValue":H[14]||(H[14]=p=>a.value.PreDown=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PreDown]])]),f("div",jd,[f("label",Ud,$(z.$t("modals.interfaceedit.postdown")),1),g1(f("textarea",{"onUpdate:modelValue":H[15]||(H[15]=p=>a.value.PostDown=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PostDown]])])]),f("fieldset",null,[qd,f("div",Wd,[g1(f("input",{"onUpdate:modelValue":H[16]||(H[16]=p=>a.value.Disabled=p),class:"form-check-input",type:"checkbox"},null,512),[[t5,a.value.Disabled]]),Bd]),f("div",Kd,[g1(f("input",{"onUpdate:modelValue":H[17]||(H[17]=p=>a.value.SaveConfig=p),checked:"",class:"form-check-input",type:"checkbox"},null,512),[[t5,a.value.SaveConfig]]),Zd])])]),f("div",Yd,[f("fieldset",null,[Gd,f("div",Xd,[f("label",Qd,$(z.$t("modals.interfaceedit.defaults.endpoint")),1),g1(f("input",{"onUpdate:modelValue":H[18]||(H[18]=p=>a.value.PeerDefEndpoint=p),class:"form-control",placeholder:"Endpoint Addresses",type:"text"},null,512),[[S1,a.value.PeerDefEndpoint]]),Jd]),f("div",cz,[f("label",ez,$(z.$t("modals.interfaceedit.defaults.networks")),1),g1(f("input",{"onUpdate:modelValue":H[19]||(H[19]=p=>a.value.PeerDefNetworkStr=p),class:"form-control",placeholder:"Network Addresses",type:"text"},null,512),[[S1,a.value.PeerDefNetworkStr]]),tz]),f("div",sz,[f("label",lz,$(z.$t("modals.interfaceedit.defaults.allowedips")),1),g1(f("input",{"onUpdate:modelValue":H[20]||(H[20]=p=>a.value.PeerDefAllowedIPsStr=p),class:"form-control",placeholder:"Listen Port",type:"text"},null,512),[[S1,a.value.PeerDefAllowedIPsStr]])]),f("div",nz,[f("label",rz,$(z.$t("modals.interfaceedit.defaults.dns")),1),g1(f("input",{"onUpdate:modelValue":H[21]||(H[21]=p=>a.value.PeerDefDnsStr=p),class:"form-control",placeholder:"DNS Servers",type:"text"},null,512),[[S1,a.value.PeerDefDnsStr]])]),f("div",az,[f("label",iz,$(z.$t("modals.interfaceedit.defaults.dnssearch")),1),g1(f("input",{"onUpdate:modelValue":H[22]||(H[22]=p=>a.value.PeerDefDnsSearchStr=p),class:"form-control",placeholder:"DNS Search prefix",type:"text"},null,512),[[S1,a.value.PeerDefDnsSearchStr]])]),f("div",oz,[f("div",fz,[f("label",uz,$(z.$t("modals.interfaceedit.defaults.mtu")),1),g1(f("input",{"onUpdate:modelValue":H[23]||(H[23]=p=>a.value.PeerDefMtu=p),class:"form-control",placeholder:"Client MTU (0 = default)",type:"number"},null,512),[[S1,a.value.PeerDefMtu]])]),f("div",hz,[f("label",mz,$(z.$t("modals.interfaceedit.defaults.firewallmark")),1),g1(f("input",{"onUpdate:modelValue":H[24]||(H[24]=p=>a.value.PeerDefFirewallMark=p),class:"form-control",placeholder:"Firewall Mark (0 = default)",type:"number"},null,512),[[S1,a.value.PeerDefFirewallMark]])])]),f("div",dz,[f("div",zz,[f("label",Cz,$(z.$t("modals.interfaceedit.defaults.routingtable")),1),g1(f("input",{"onUpdate:modelValue":H[25]||(H[25]=p=>a.value.PeerDefRoutingTable=p),class:"form-control",placeholder:"Routing Table (0 = default)",type:"number"},null,512),[[S1,a.value.PeerDefRoutingTable]])]),f("div",vz,[f("label",Hz,$(z.$t("modals.interfaceedit.defaults.keepalive")),1),g1(f("input",{"onUpdate:modelValue":H[26]||(H[26]=p=>a.value.PeerDefPersistentKeepalive=p),class:"form-control",placeholder:"Persistent Keepalive (0 = default)",type:"number"},null,512),[[S1,a.value.PeerDefPersistentKeepalive]])])])]),f("fieldset",null,[Vz,f("div",Mz,[f("label",pz,$(z.$t("modals.interfaceedit.defaults.preup")),1),g1(f("textarea",{"onUpdate:modelValue":H[27]||(H[27]=p=>a.value.PeerDefPreUp=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PeerDefPreUp]])]),f("div",Lz,[f("label",gz,$(z.$t("modals.interfaceedit.defaults.postup")),1),g1(f("textarea",{"onUpdate:modelValue":H[28]||(H[28]=p=>a.value.PeerDefPostUp=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PeerDefPostUp]])]),f("div",bz,[f("label",_z,$(z.$t("modals.interfaceedit.defaults.predown")),1),g1(f("textarea",{"onUpdate:modelValue":H[29]||(H[29]=p=>a.value.PeerDefPreDown=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PeerDefPreDown]])]),f("div",yz,[f("label",Sz,$(z.$t("modals.interfaceedit.defaults.postdown")),1),g1(f("textarea",{"onUpdate:modelValue":H[30]||(H[30]=p=>a.value.PeerDefPostDown=p),class:"form-control",rows:"2"},null,512),[[S1,a.value.PeerDefPostDown]])])])])])]),footer:V2(()=>[f("div",wz,[t.interfaceId!=="#NEW#"?(C1(),b1("button",{key:0,class:"btn btn-danger me-1",type:"button",onClick:i2(C,["prevent"])},"Delete",8,Ez)):R1("",!0)]),f("button",{class:"btn btn-primary me-1",type:"button",onClick:i2(u,["prevent"])},"Save",8,kz),f("button",{class:"btn btn-secondary",type:"button",onClick:i2(o,["prevent"])},"Discard",8,Az)]),_:1},8,["title","visible"]))}},Tz={class:"page-header row"},Oz={class:"col-12 col-lg-8"},xz={class:"col-12 col-lg-4 text-end"},Iz=f("div",{class:"form-group"},null,-1),$z={class:"form-group"},Nz={class:"input-group mb-3"},Dz=f("i",{class:"fa-solid fa-plus-circle"},null,-1),Rz=[Dz],Fz=["disabled"],jz={key:0,value:"nothing"},Uz=["value"],qz={key:0,class:"row"},Wz={class:"col-lg-12"},Bz={class:"mt-5"},Kz={key:1,class:"row"},Zz={class:"col-lg-12"},Yz={class:"card border-secondary mb-4",style:{"min-height":"15rem"}},Gz={class:"card-header"},Xz={class:"row"},Qz={class:"col-12 col-lg-8"},Jz={class:"col-12 col-lg-4 text-lg-end"},cC=Pa('',3),eC=f("i",{class:"fas fa-cog"},null,-1),tC=[eC],sC={class:"card-body d-flex flex-column"},lC={key:0,class:"row"},nC={class:"col-sm-6"},rC={class:"table table-sm table-borderless device-status-table"},aC={class:"col-sm-6"},iC={class:"table table-sm table-borderless device-status-table"},oC={key:1,class:"row"},fC={class:"col-sm-6"},uC={class:"table table-sm table-borderless device-status-table"},hC={class:"col-sm-6"},mC={class:"table table-sm table-borderless device-status-table"},dC={key:2,class:"row"},zC={class:"col-sm-6"},CC={class:"table table-sm table-borderless device-status-table"},vC={class:"col-sm-6"},HC={class:"table table-sm table-borderless device-status-table"},VC={key:2,class:"mt-4 row"},MC={class:"col-12 col-lg-5"},pC={key:0,class:"mt-2"},LC={key:1,class:"mt-2"},gC={class:"col-12 col-lg-4 text-lg-end"},bC={class:"form-group d-inline"},_C={class:"input-group mb-3"},yC=f("button",{class:"input-group-text btn btn-primary",title:"Search"},[f("i",{class:"fa-solid fa-search"})],-1),SC={class:"col-12 col-lg-3 text-lg-end"},wC={key:0,class:"btn btn-primary",href:"#",title:"Send mail to all peers"},EC=f("i",{class:"fa fa-paper-plane"},null,-1),kC=[EC],AC=f("a",{class:"btn btn-primary ms-2",href:"#",title:"Add multiple peers"},[f("i",{class:"fa fa-plus me-1"}),f("i",{class:"fa fa-users"})],-1),PC=f("i",{class:"fa fa-plus me-1"},null,-1),TC=f("i",{class:"fa fa-user"},null,-1),OC=[PC,TC],xC={key:3,class:"mt-2 table-responsive"},IC={key:0},$C={key:1,id:"peerTable",class:"table table-sm"},NC=f("th",{scope:"col"},[f("input",{id:"flexCheckDefault",class:"form-check-input",title:"Select all",type:"checkbox",value:""})],-1),DC={scope:"col"},RC={scope:"col"},FC={scope:"col"},jC={scope:"col"},UC={key:0,scope:"col"},qC={scope:"col"},WC=f("th",{scope:"col"},null,-1),BC=f("th",{scope:"row"},[f("input",{id:"flexCheckDefault",class:"form-check-input",type:"checkbox",value:""})],-1),KC={key:0},ZC={class:"text-center"},YC=["onClick"],GC=f("i",{class:"fas fa-eye me-2"},null,-1),XC=[GC],QC=["onClick"],JC=f("i",{class:"fas fa-cog"},null,-1),cv=[JC],ev={key:4},tv={key:5,class:"mt-3"},sv={class:"row"},lv={class:"col-6"},nv={class:"pagination pagination-sm"},rv=["onClick"],av={class:"col-6"},iv={class:"form-group row"},ov={class:"col-sm-6 col-form-label text-end",for:"paginationSelector"},fv={class:"col-sm-6"},uv=f("option",{value:"10"},"10",-1),hv=f("option",{value:"25"},"25",-1),mv=f("option",{value:"50"},"50",-1),dv=f("option",{value:"100"},"100",-1),zv={value:"999999999"},ws={__name:"InterfaceView",setup(c){const e=l8(),t=x7(),s=a2(""),l=a2(""),n=a2("");return s8(async()=>{await e.LoadInterfaces(),await t.LoadPeers()}),(r,a)=>(C1(),b1(Y1,null,[W1($u,{peerId:s.value,visible:s.value!=="",onClose:a[0]||(a[0]=i=>s.value="")},null,8,["peerId","visible"]),W1(Km,{peerId:l.value,visible:l.value!=="",onClose:a[1]||(a[1]=i=>l.value="")},null,8,["peerId","visible"]),W1(Pz,{interfaceId:n.value,visible:n.value!=="",onClose:a[2]||(a[2]=i=>n.value="")},null,8,["interfaceId","visible"]),f("div",Tz,[f("div",Oz,[f("h1",null,$(r.$t("interfaces.h1")),1)]),f("div",xz,[Iz,f("div",$z,[f("div",Nz,[f("button",{class:"input-group-text btn btn-primary",title:"Add new interface",onClick:a[3]||(a[3]=i2(i=>n.value="#NEW#",["prevent"]))},Rz),g1(f("select",{"onUpdate:modelValue":a[4]||(a[4]=i=>Z(e).selected=i),disabled:Z(e).Count===0,class:"form-select",onChange:a[5]||(a[5]=i=>Z(t).LoadPeers())},[Z(e).Count===0?(C1(),b1("option",jz,$(r.$t("interfaces.notAvailable")),1)):R1("",!0),(C1(!0),b1(Y1,null,O4(Z(e).All,i=>(C1(),b1("option",{key:i.Identifier,value:i.Identifier},$(i.Identifier),9,Uz))),128))],40,Fz),[[F0,Z(e).selected]])])])])]),Z(e).Count===0?(C1(),b1("div",qz,[f("div",Wz,[f("div",Bz,[f("h4",null,$(r.$t("interfaces.noInterface.h1")),1),f("p",null,$(r.$t("interfaces.noInterface.message")),1)])])])):R1("",!0),Z(e).Count!==0?(C1(),b1("div",Kz,[f("div",Zz,[f("div",Yz,[f("div",Gz,[f("div",Xz,[f("div",Qz,[r2($(r.$t("interfaces.statusBox.h1"))+" ",1),f("strong",null,$(Z(e).GetSelected.Identifier),1),r2(" ("+$(Z(e).GetSelected.Mode)+" "+$(r.$t("interfaces.statusBox.mode"))+") ",1)]),f("div",Jz,[cC,f("a",{class:"ms-5 btn-link",href:"#",title:"Edit interface settings",onClick:a[6]||(a[6]=i2(i=>n.value=Z(e).GetSelected.Identifier,["prevent"]))},tC)])])]),f("div",sC,[Z(e).GetSelected.Mode==="server"?(C1(),b1("div",lC,[f("div",nC,[f("table",rC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.key"))+":",1),f("td",null,$(Z(e).GetSelected.PublicKey),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.endpoint"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefEndpoint),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.port"))+":",1),f("td",null,$(Z(e).GetSelected.ListenPort),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.peers"))+":",1),f("td",null,$(Z(e).GetSelected.EnabledPeers),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.totalPeers"))+":",1),f("td",null,$(Z(e).GetSelected.TotalPeers),1)])])])]),f("div",aC,[f("table",iC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.ip"))+":",1),f("td",null,$(Z(e).GetSelected.Addresses),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.allowedIP"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefAllowedIPsStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.dnsServers"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefDnsStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.mtu"))+":",1),f("td",null,$(Z(e).GetSelected.Mtu),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.intervall"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefPersistentKeepalive),1)])])])])])):R1("",!0),Z(e).GetSelected.Mode==="client"?(C1(),b1("div",oC,[f("div",fC,[f("table",uC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.key"))+":",1),f("td",null,$(Z(e).GetSelected.PublicKey),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.endpoint"))+":",1),f("td",null,$(Z(e).GetSelected.InterfacePeers),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.totalPeers"))+":",1),f("td",null,$(Z(e).GetSelected.TotalPeers),1)])])])]),f("div",hC,[f("table",mC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.ip"))+":",1),f("td",null,$(Z(e).GetSelected.AddressStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.dnsServers"))+":",1),f("td",null,$(Z(e).GetSelected.DnsStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.mtu"))+":",1),f("td",null,$(Z(e).GetSelected.Mtu),1)])])])])])):R1("",!0),Z(e).GetSelected.Mode==="any"?(C1(),b1("div",dC,[f("div",zC,[f("table",CC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.key"))+":",1),f("td",null,$(Z(e).GetSelected.PublicKey),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.endpoint"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefEndpoint),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.port"))+":",1),f("td",null,$(Z(e).GetSelected.ListenPort),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.peers"))+":",1),f("td",null,$(Z(e).GetSelected.EnabledPeers),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.totalPeers"))+":",1),f("td",null,$(Z(e).GetSelected.TotalPeers),1)])])])]),f("div",vC,[f("table",HC,[f("tbody",null,[f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.ip"))+":",1),f("td",null,$(Z(e).GetSelected.Addresses),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.allowedIP"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefAllowedIPsStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.dnsServers"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefDnsStr),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.mtu"))+":",1),f("td",null,$(Z(e).GetSelected.Mtu),1)]),f("tr",null,[f("td",null,$(r.$t("interfaces.statusBox.intervall"))+":",1),f("td",null,$(Z(e).GetSelected.PeerDefPersistentKeepalive),1)])])])])])):R1("",!0)])])])])):R1("",!0),Z(e).Count!==0?(C1(),b1("div",VC,[f("div",MC,[Z(e).GetSelected.Mode==="server"?(C1(),b1("h2",pC,$(r.$t("interfaces.h2")),1)):(C1(),b1("h2",LC,$(r.$t("interfaces.h2-client")),1))]),f("div",gC,[f("div",bC,[f("div",_C,[g1(f("input",{"onUpdate:modelValue":a[7]||(a[7]=i=>Z(t).filter=i),class:"form-control",placeholder:"Search...",type:"text",onKeyup:a[8]||(a[8]=(...i)=>Z(t).afterPageSizeChange&&Z(t).afterPageSizeChange(...i))},null,544),[[S1,Z(t).filter]]),yC])])]),f("div",SC,[Z(e).GetSelected.Mode==="server"&&Z(t).Count!==0?(C1(),b1("a",wC,kC)):R1("",!0),AC,f("a",{class:"btn btn-primary ms-2",href:"#",title:"Add a peer",onClick:a[9]||(a[9]=i2(i=>l.value="#NEW#",["prevent"]))},OC)])])):R1("",!0),Z(e).Count!==0?(C1(),b1("div",xC,[Z(t).Count===0?(C1(),b1("div",IC,[f("h4",null,$(r.$t("interfaces.noPeerSelect.h4")),1),f("p",null,$(r.$t("interfaces.noPeerSelect.message")),1)])):R1("",!0),Z(t).Count!==0?(C1(),b1("table",$C,[f("thead",null,[f("tr",null,[NC,f("th",DC,$(r.$t("interfaces.tableHeadings[0]")),1),f("th",RC,$(r.$t("interfaces.tableHeadings[1]")),1),f("th",FC,$(r.$t("interfaces.tableHeadings[2]")),1),f("th",jC,$(r.$t("interfaces.tableHeadings[3]")),1),Z(e).GetSelected.Mode==="client"?(C1(),b1("th",UC,$(r.$t("interfaces.tableHeadings[4]")),1)):R1("",!0),f("th",qC,$(r.$t("interfaces.tableHeadings[5]")),1),WC])]),f("tbody",null,[(C1(!0),b1(Y1,null,O4(Z(t).FilteredAndPaged,i=>(C1(),b1("tr",{key:i.Identifier},[BC,f("td",null,$(i.DisplayName),1),f("td",null,$(i.Identifier),1),f("td",null,$(i.UserIdentifier),1),f("td",null,[(C1(!0),b1(Y1,null,O4(i.Addresses,o=>(C1(),b1("span",{key:o,class:"badge rounded-pill bg-light"},$(o),1))),128))]),Z(e).GetSelected.Mode==="client"?(C1(),b1("td",KC,$(i.Endpoint),1)):R1("",!0),f("td",null,$(i.LastConnected),1),f("td",ZC,[f("a",{href:"#",title:"Show peer",onClick:i2(o=>s.value=i.Identifier,["prevent"])},XC,8,YC),f("a",{href:"#",title:"Edit peer",onClick:i2(o=>l.value=i.Identifier,["prevent"])},cv,8,QC)])]))),128))])])):R1("",!0)])):R1("",!0),Z(e).Count!==0?(C1(),b1("hr",ev)):R1("",!0),Z(e).Count!==0?(C1(),b1("div",tv,[f("div",sv,[f("div",lv,[f("ul",nv,[f("li",{class:b2([{disabled:Z(t).pageOffset===0},"page-item"])},[f("a",{class:"page-link",onClick:a[10]||(a[10]=(...i)=>Z(t).previousPage&&Z(t).previousPage(...i))},"«")],2),(C1(!0),b1(Y1,null,O4(Z(t).pages,i=>(C1(),b1("li",{key:i,class:b2([{active:Z(t).currentPage===i},"page-item"])},[f("a",{class:"page-link",onClick:o=>Z(t).gotoPage(i)},$(i),9,rv)],2))),128)),f("li",{class:b2([{disabled:!Z(t).hasNextPage},"page-item"])},[f("a",{class:"page-link",onClick:a[11]||(a[11]=(...i)=>Z(t).nextPage&&Z(t).nextPage(...i))},"»")],2)])]),f("div",av,[f("div",iv,[f("label",ov,$(r.$t("interfaces.pagination.size"))+":",1),f("div",fv,[g1(f("select",{"onUpdate:modelValue":a[12]||(a[12]=i=>Z(t).pageSize=i),class:"form-select",onClick:a[13]||(a[13]=i=>Z(t).afterPageSizeChange())},[uv,hv,mv,dv,f("option",zv,$(r.$t("interfaces.pagination.all")),1)],512),[[F0,Z(t).pageSize,void 0,{number:!0}]])])])])])])):R1("",!0)],64))}},Cv=Object.freeze(Object.defineProperty({__proto__:null,default:ws},Symbol.toStringTag,{value:"Module"})),R4=Oo({history:Xi(),routes:[{path:"/",name:"home",component:Kf},{path:"/login",name:"login",component:pu},{path:"/interface",name:"interface",component:ws},{path:"/interfaces",name:"interfaces",component:()=>qc(()=>Promise.resolve().then(()=>Cv),void 0)},{path:"/users",name:"users",component:()=>qc(()=>import("./UserView-f9bf06a4.js"),[])}],linkActiveClass:"active",linkExactActiveClass:"exact-active"});R4.beforeEach(async c=>{const e=o6();if("wgLoginState"in c.query&&!e.IsAuthenticated){const l=c.query.wgLoginState,n=e.ReturnUrl;if(console.log("Oauth login callback:",l),l==="success")try{const r=await e.LoadSession();return console.log("Oauth login completed for UID:",r),console.log("Continuing to:",n),t2({title:"Logged in",text:"Authentication suceeded!",type:"success"}),e.ResetReturnUrl(),n}catch{return t2({title:"Login failed!",text:"Oauth session is invalid!",type:"error"}),"/login"}else return t2({title:"Login failed!",text:"Authentication via Oauth failed!",type:"error"}),"/login"}if(!["/","/login"].includes(c.path)&&!e.IsAuthenticated)return e.SetReturnUrl(c.fullPath),"/login"});const o6=L5({id:"auth",state:()=>({user:JSON.parse(localStorage.getItem("user")),providers:[],returnUrl:localStorage.getItem("returnUrl")}),getters:{UserIdentifier: c=>{var e;return((e=c.user)==null?void 0:e.Identifier)||"unknown"},User: c=>c.user,LoginProviders: c=>c.providers,IsAuthenticated: c=>c.user!=null,IsAdmin: c=>{var e;return((e=c.user)==null?void 0:e.IsAdmin)||!1},ReturnUrl: c=>c.returnUrl||"/"},actions:{SetReturnUrl(c){this.returnUrl=c,localStorage.setItem("returnUrl",c)},ResetReturnUrl(){this.returnUrl=null,localStorage.removeItem("returnUrl")},async LoadProviders(){F2.get("/auth/providers").then(c=>this.providers=c).catch(c=>{this.providers=[],console.log("Failed to load auth providers: ",c),t2({title:"Backend Connection Failure",text:"Failed to load external authentication providers!"})})},async LoadSession(){return F2.get("/auth/session").then(c=>c.LoggedIn===!0?(this.ResetReturnUrl(),this.setUserInfo(c),c.UserIdentifier):(this.setUserInfo(null),Promise.reject(new Error("session not authenticated")))).catch(c=>(this.setUserInfo(null),Promise.reject(c)))},async Login(c, e){return F2.post("/auth/login",{username:c,password:e}).then(t=>(this.ResetReturnUrl(),this.setUserInfo(t),t.Identifier)).catch(t=>(console.log("Login failed:",t),this.setUserInfo(null),Promise.reject(new Error("login failed"))))},async Logout(){this.setUserInfo(null),this.ResetReturnUrl();try{await F2.post("/auth/logout")}catch(c){console.log("Logout request failed:",c)}t2({title:"Logged Out",text:"Logout successful!",type:"warn"}),await R4.push("/login")},setUserInfo(c){c?("UserIdentifier"in c?this.user={Identifier:c.UserIdentifier,Firstname:c.UserFirstname,Lastname:c.UserLastname,Email:c.UserEmail,IsAdmin:c.IsAdmin}:this.user={Identifier:c.Identifier,Firstname:c.Firstname,Lastname:c.Lastname,Email:c.Email,IsAdmin:c.IsAdmin},localStorage.setItem("user",JSON.stringify(this.user))):(this.user=null,localStorage.removeItem("user"))}}});const vv={class:"navbar navbar-expand-lg navbar-dark bg-primary"},Hv={class:"container-fluid"},Vv=f("a",{class:"navbar-brand",href:"/"},[f("img",{alt:"WireGuard Portal",src:Ai})],-1),Mv=f("button",{"aria-controls":"navbarColor01","aria-expanded":"false","aria-label":"Toggle navigation",class:"navbar-toggler","data-bs-target":"#navbarTop","data-bs-toggle":"collapse",type:"button"},[f("span",{class:"navbar-toggler-icon"})],-1),pv={id:"navbarTop",class:"collapse navbar-collapse"},Lv={class:"navbar-nav me-auto"},gv={class:"nav-item"},bv={key:0,class:"nav-item"},_v={key:1,class:"nav-item"},yv={class:"navbar-nav d-flex justify-content-end"},Sv={key:0,class:"nav-item dropdown"},wv={"aria-expanded":"false","aria-haspopup":"true",class:"nav-link dropdown-toggle","data-bs-toggle":"dropdown",href:"#",role:"button"},Ev={class:"dropdown-menu"},kv={class:"dropdown-item",href:"/user/profile"},Av=f("i",{class:"fas fa-user"},null,-1),Pv=f("div",{class:"dropdown-divider"},null,-1),Tv=f("i",{class:"fas fa-sign-out-alt"},null,-1),Ov={key:1,class:"nav-item"},xv=f("i",{class:"fas fa-sign-in-alt fa-sm fa-fw me-2"},null,-1),Iv={class:"container mt-5 flex-shrink-0"},$v={class:"page-footer mt-auto"},Nv={class:"container mt-5"},Dv={class:"row align-items-center"},Rv=f("div",{class:"col-6"},[r2("Powered by "),f("img",{alt:"Vue.JS",height:"20",src:Pi})],-1),Fv={class:"col-6 text-end"},jv={"aria-label":"{{ $t('menu.lang') }}",class:"btn-group",role:"group"},Uv={class:"btn-group",role:"group"},qv={"aria-expanded":"false","aria-haspopup":"true",class:"btn btn btn-secondary pe-0","data-bs-toggle":"dropdown",type:"button"},Wv={"aria-labelledby":"btnGroupDrop3",class:"dropdown-menu",style:{}},Bv=f("span",{class:"fi fi-us"},null,-1),Kv=f("span",{class:"fi fi-de"},null,-1),Zv=f("span",{class:"fi fi-es"},null,-1),Yv={__name:"App",setup(c){const e=V3().appContext.config.globalProperties,t=o6(),s=Hs();s8(async()=>{console.log("Starting WireGuard Portal frontend..."),await s.LoadSecurityProperties(),await t.LoadProviders();let r=t.IsAuthenticated;try{await t.LoadSession()}catch{r&&await t.Logout()}console.log("WireGuard Portal ready!")});const l=function(r){e.$i18n.locale!==r&&(localStorage.setItem("wgLang",r),e.$i18n.locale=r)},n=F1(()=>{let r=e.$i18n.locale.toLowerCase();return r==="en"&&(r="us"),"fi-"+r});return(r, a)=>{const i=Pt("notifications");return C1(),b1(Y1,null,[W1(i,{duration:3e3,"ignore-duplicates":!0,position:"top right"}),f("nav",vv,[f("div",Hv,[Vv,Mv,f("div",pv,[f("ul",Lv,[f("li",gv,[W1(Z(w6),{to:{name:"home"},class:"nav-link"},{default:V2(()=>[r2($(r.$t("menu.home")),1)]),_:1})]),Z(t).IsAuthenticated&&Z(t).IsAdmin?(C1(),b1("li",bv,[W1(Z(w6),{to:{name:"interfaces"},class:"nav-link"},{default:V2(()=>[r2($(r.$t("menu.interfaces")),1)]),_:1})])):R1("",!0),Z(t).IsAuthenticated&&Z(t).IsAdmin?(C1(),b1("li",_v,[W1(Z(w6),{to:{name:"users"},class:"nav-link"},{default:V2(()=>[r2($(r.$t("menu.users")),1)]),_:1})])):R1("",!0)]),f("div",yv,[Z(t).IsAuthenticated?(C1(),b1("div",Sv,[f("a",wv,$(Z(t).User.Firstname)+" "+$(Z(t).User.Lastname),1),f("div",Ev,[f("a",kv,[Av,r2(" "+$(r.$t("menu.profile")),1)]),Pv,f("a",{class:"dropdown-item",href:"#",onClick:a[0]||(a[0]=i2((...o)=>Z(t).Logout&&Z(t).Logout(...o),["prevent"]))},[Tv,r2(" "+$(r.$t("menu.logout")),1)])])])):R1("",!0),Z(t).IsAuthenticated?R1("",!0):(C1(),b1("div",Ov,[W1(Z(w6),{to:{name:"login"},class:"nav-link"},{default:V2(()=>[xv,r2($(r.$t("menu.login")),1)]),_:1})]))])])])]),f("div",Iv,[W1(Z(Cs))]),f("footer",$v,[f("div",Nv,[f("div",Dv,[Rv,f("div",Fv,[f("div",jv,[f("div",Uv,[f("button",qv,[f("span",{class:b2([Z(n),"fi"])},null,2)]),f("div",Wv,[f("a",{class:"dropdown-item",href:"#",onClick:a[1]||(a[1]=i2(o=>l("en"),["prevent"]))},[Bv,r2(" English")]),f("a",{class:"dropdown-item",href:"#",onClick:a[2]||(a[2]=i2(o=>l("de"),["prevent"]))},[Kv,r2(" Deutsch")]),f("a",{class:"dropdown-item",href:"#",onClick:a[3]||(a[3]=i2(o=>l("es"),["prevent"]))},[Zv,r2(" Español")])])])])])])])])],64)}}},Gv="Hallo Welt!",Xv={home:"Home",interfaces:"Schnittstellen",firstname:"Vorname",surname:"Nachname",login:"Anmelden",logout:"Abmelden",admin:"Verwaltung",user:"Nutzer",profile:"Profil",lang:"Sprache umschalten"},Qv={h1:"WireGuard® VPN Portal",abstract:"WireGuard® ist ein extrem einfaches, aber dennoch schnelles und modernes VPN, das modernste Kryptographie nutzt. Es zielt darauf ab, schneller, einfacher, schlanker und nützlicher als IPsec zu sein, während es die massiven Kopfschmerzen vermeidet. Es soll wesentlich leistungsfähiger sein als OpenVPN.",info:"Informationen",installation:{h1:"VPN Installation",h2:"Installation",instruct:"Die Installationsanweisungen für die Client-Software finden Sie auf der offiziellen WireGuard-Website.",btn:"Anleitung öffnen"},"about-wg":{instruct:"WireGuard® ist ein extrem einfaches, aber schnelles und modernes VPN, das modernste Kryptographie verwendet.",h1:"Über WireGuard",h2:"Über",btn:"Details"},"about-portal":{instruct:"WireGuard Portal ist ein einfaches, webbasiertes Konfigurationsportal für WireGuard.",h1:"Über WireGuard Portal",h2:"WireGuard-Portal",btn:"Details"},profiles:{h1:"VPN Profile",abstract:"Über Ihr Benutzerprofil können Sie auf Ihre persönlichen VPN-Konfigurationen zugreifen und diese herunterladen.",instruct:"Um alle Ihre konfigurierten Profile zu finden, klicken Sie auf die Schaltfläche unten.",btn:"Mein Profil öffnen"},admin:{h1:"Verwaltungsbereich",abstract:"Im Administrationsbereich können Sie VPN-Zugänge und die Serverschnittstelle sowie die Benutzer, die sich am VPN-Portal anmelden dürfen, verwalten.",instruct:"Um alle Ihre konfigurierten Profile zu finden, klicken Sie auf die Schaltfläche unten.","btn-1":"Serververwaltung öffnen","btn-2":"Benutzerverwaltung öffnen"}},Jv={h1:"Schnittstellenverwaltung",h2:"Aktuelle VPN-Geräte","h2-client":"Aktuelle Endpunkte",tableHeadings:["Name","Kennung","Benutzer","IPs","Endpunkt","Handschlag"],noInterface:{h1:"Keine Schnittstellen gefunden...",message:"Klicken Sie auf die Plus-Schaltfläche oben, um eine neue WireGuard-Schnittstelle zu erstellen."},notAvailable:"Keine Schnittstelle verfügbar",statusBox:{h1:"Schnittstellenstatus für",key:"Öffentlicher Schlüssel",mode:"Modus",endpoint:"Öffentlicher Endpunkt",port:"Lauschender Port",peers:"Aktivierte Zugänge",totalPeers:"Alle Zugänge",ip:"IP-Adresse",allowedIP:"Standardmäßig erlaubte IPs",dnsServers:"DNS-Server",mtu:"Vorgegebene MTU",intervall:"Standard-Keepalive-Intervall"},noPeerSelect:{h4:"Keine Zugänge für die ausgewählte Schnittstelle...",message:"Klicken Sie auf die Plus-Schaltfläche oben, um eine neue VPN-Schnittstelle zu erstellen."},pagination:{size:"Anzahl",all:"Alle (langsam)"}},cH={please:"Bitte melden Sie sich an",username:"Benutzername",userMessage:"Bitte geben Sie Ihren Benutzernamen ein",pass:"Kennwort",passMessage:"Bitte geben Sie Ihr Passwort ein",btn:"Sign in"},eH={hello:Gv,menu:Xv,home:Qv,interfaces:Jv,login:cH},tH="Hello World!",sH={home:"Home",interfaces:"Interfaces",users:"Users",firstname:"Firstname",lastname:"Lastname",login:"Login",lang:"Toggle Language"},lH={h1:"WireGuard® VPN Portal",info:"More Information",abstract:"WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN.",installation:{instruct:"Installation instructions for client software can be found on the official WireGuard website.",h1:"WireGuard Installation",h2:"Installation",btn:"Open Instructions"},"about-wg":{instruct:"WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography.",h1:"About WireGuard",h2:"About",btn:"More"},"about-portal":{instruct:"WireGuard Portal is a simple, web based configuration portal for WireGuard.",h1:"About WireGuard Portal",h2:"WireGuard Portal",btn:"More"},profiles:{h1:"VPN Profiles",abstract:"You can access and download your personal VPN configurations via your Userprofile.",instruct:"To find all your configured profiles click on the button below.",btn:"Open my profile"},admin:{h1:"Administration Area",abstract:"In the administration area you can manage WireGuard peers and the server interface as well as users that are allowed to log in to the WireGuard Portal.",instruct:"To find all your configured profiles click on the button below.","btn-1":"Open Server Administration","btn-2":"Open User Administration"}},nH={h1:"Interface Administration",h2:"Current VPN Peers","h2-client":"Current Endpoints",tableHeadings:["Name","Identifier","User","IPs","Endpoint","Handshake"],noInterface:{h1:"No interfaces found...",message:"Click the plus button above to create a new WireGuard interface."},notAvailable:"No Interface available",statusBox:{h1:"Interface status for",mode:"mode",key:"Public Key",endpoint:"Public Endpoint",port:"Listening Port",peers:"Enabled Peers",totalPeers:"Total Peers",ip:"IP Address",allowedIP:"Default allowed IPs",dnsServers:"DNS Servers",mtu:"Default MTU",interval:"Default Keepalive Interval"},noPeerSelect:{h4:"No peers for the selected interface...",message:"Click the plus button above to create a new WireGuard interface."},pagination:{size:"Number of Elements",all:"All (slow)"},peer:{new:"Create new peer",edit:"Edit peer"},interface:{new:"Create new interface",edit:"Edit interface"},endpoint:{new:"Create new endpoint",edit:"Edit endpoint"}},rH={please:"Please sign in",username:"Username",userMessage:"Please enter your username",pass:"Password",passMessage:"Please enter your password",btn:"Sign in"},aH={h1:"User Administration",id:"ID",email:"eMail",firstname:"Firstname",lastname:"Lastname",source:"Source",peers:"Peers",admin:"Admin",addUser:"Add User",addMulti:"Add Multiple Users"},iH={peeredit:{privatekey:"Private Key"}},oH={hello:tH,menu:sH,home:lH,interfaces:nH,login:rH,user:aH,modals:iH},fH="Hola mundo!",uH={hello:fH};function hH(){let c=localStorage.getItem("wgLang");return c||(c="en"),c}const mH=nm({legacy:!1,globalInjection:!0,allowComposition:!0,locale:hH(),fallbackLocale:"en",messages:{de:eH,en:oH,es:uH}});var p2="top",E2="bottom",k2="right",L2="left",S5="auto",f6=[p2,E2,k2,L2],H4="start",X4="end",Es="clippingParents",j7="viewport",A4="popper",ks="reference",t7=f6.reduce(function(c, e){return c.concat([e+"-"+H4,e+"-"+X4])},[]),U7=[].concat(f6,[S5]).reduce(function(c, e){return c.concat([e,e+"-"+H4,e+"-"+X4])},[]),As="beforeRead",Ps="read",Ts="afterRead",Os="beforeMain",xs="main",Is="afterMain",$s="beforeWrite",Ns="write",Ds="afterWrite",Rs=[As,Ps,Ts,Os,xs,Is,$s,Ns,Ds];function n3(c){return c?(c.nodeName||"").toLowerCase():null}function $2(c){if(c==null)return window;if(c.toString()!=="[object Window]"){var e=c.ownerDocument;return e&&e.defaultView||window}return c}function V4(c){var e=$2(c).Element;return c instanceof e||c instanceof Element}function x2(c){var e=$2(c).HTMLElement;return c instanceof e||c instanceof HTMLElement}function q7(c){if(typeof ShadowRoot>"u")return!1;var e=$2(c).ShadowRoot;return c instanceof e||c instanceof ShadowRoot}function dH(c){var e=c.state;Object.keys(e.elements).forEach(function(t){var s=e.styles[t]||{},l=e.attributes[t]||{},n=e.elements[t];!x2(n)||!n3(n)||(Object.assign(n.style,s),Object.keys(l).forEach(function(r){var a=l[r];a===!1?n.removeAttribute(r):n.setAttribute(r,a===!0?"":a)}))})}function zH(c){var e=c.state,t={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,t.popper),e.styles=t,e.elements.arrow&&Object.assign(e.elements.arrow.style,t.arrow),function(){Object.keys(e.elements).forEach(function(s){var l=e.elements[s],n=e.attributes[s]||{},r=Object.keys(e.styles.hasOwnProperty(s)?e.styles[s]:t[s]),a=r.reduce(function(i, o){return i[o]="",i},{});!x2(l)||!n3(l)||(Object.assign(l.style,a),Object.keys(n).forEach(function(i){l.removeAttribute(i)}))})}}const W7={name:"applyStyles",enabled:!0,phase:"write",fn:dH,effect:zH,requires:["computeStyles"]};function t3(c){return c.split("-")[0]}var v4=Math.max,a5=Math.min,Q4=Math.round;function s7(){var c=navigator.userAgentData;return c!=null&&c.brands?c.brands.map(function(e){return e.brand+"/"+e.version}).join(" "):navigator.userAgent}function Fs(){return!/^((?!chrome|android).)*safari/i.test(s7())}function J4(c, e, t){e===void 0&&(e=!1),t===void 0&&(t=!1);var s=c.getBoundingClientRect(),l=1,n=1;e&&x2(c)&&(l=c.offsetWidth>0&&Q4(s.width)/c.offsetWidth||1,n=c.offsetHeight>0&&Q4(s.height)/c.offsetHeight||1);var r=V4(c)?$2(c):window,a=r.visualViewport,i=!Fs()&&t,o=(s.left+(i&&a?a.offsetLeft:0))/l,u=(s.top+(i&&a?a.offsetTop:0))/n,C=s.width/l,z=s.height/n;return{width:C,height:z,top:u,right:o+C,bottom:u+z,left:o,x:o,y:u}}function B7(c){var e=J4(c),t=c.offsetWidth,s=c.offsetHeight;return Math.abs(e.width-t)<=1&&(t=e.width),Math.abs(e.height-s)<=1&&(s=e.height),{x:c.offsetLeft,y:c.offsetTop,width:t,height:s}}function js(c, e){var t=e.getRootNode&&e.getRootNode();if(c.contains(e))return!0;if(t&&q7(t)){var s=e;do{if(s&&c.isSameNode(s))return!0;s=s.parentNode||s.host}while(s)}return!1}function M3(c){return $2(c).getComputedStyle(c)}function CH(c){return["table","td","th"].indexOf(n3(c))>=0}function Q3(c){return((V4(c)?c.ownerDocument:c.document)||window.document).documentElement}function w5(c){return n3(c)==="html"?c:c.assignedSlot||c.parentNode||(q7(c)?c.host:null)||Q3(c)}function de(c){return!x2(c)||M3(c).position==="fixed"?null:c.offsetParent}function vH(c){var e=/firefox/i.test(s7()),t=/Trident/i.test(s7());if(t&&x2(c)){var s=M3(c);if(s.position==="fixed")return null}var l=w5(c);for(q7(l)&&(l=l.host); x2(l)&&["html","body"].indexOf(n3(l))<0;){var n=M3(l);if(n.transform!=="none"||n.perspective!=="none"||n.contain==="paint"||["transform","perspective"].indexOf(n.willChange)!==-1||e&&n.willChange==="filter"||e&&n.filter&&n.filter!=="none")return l;l=l.parentNode}return null}function a8(c){for(var e=$2(c),t=de(c); t&&CH(t)&&M3(t).position==="static";)t=de(t);return t&&(n3(t)==="html"||n3(t)==="body"&&M3(t).position==="static")?e:t||vH(c)||e}function K7(c){return["top","bottom"].indexOf(c)>=0?"x":"y"}function $6(c, e, t){return v4(c,a5(e,t))}function HH(c, e, t){var s=$6(c,e,t);return s>t?t:s}function Us(){return{top:0,right:0,bottom:0,left:0}}function qs(c){return Object.assign({},Us(),c)}function Ws(c, e){return e.reduce(function(t, s){return t[s]=c,t},{})}var VH=function(e, t){return e=typeof e=="function"?e(Object.assign({},t.rects,{placement:t.placement})):e,qs(typeof e!="number"?e:Ws(e,f6))};function MH(c){var e,t=c.state,s=c.name,l=c.options,n=t.elements.arrow,r=t.modifiersData.popperOffsets,a=t3(t.placement),i=K7(a),o=[L2,k2].indexOf(a)>=0,u=o?"height":"width";if(!(!n||!r)){var C=VH(l.padding,t),z=B7(n),H=i==="y"?p2:L2,p=i==="y"?E2:k2,E=t.rects.reference[u]+t.rects.reference[i]-r[i]-t.rects.popper[u],A=r[i]-t.rects.reference[i],L=a8(n),O=L?i==="y"?L.clientHeight||0:L.clientWidth||0:0,T=E/2-A/2,_=C[H],x=O-z[u]-C[p],K=O/2-z[u]/2+T,D=$6(_,K,x),F=i;t.modifiersData[s]=(e={},e[F]=D,e.centerOffset=D-K,e)}}function pH(c){var e=c.state,t=c.options,s=t.element,l=s===void 0?"[data-popper-arrow]":s;l!=null&&(typeof l=="string"&&(l=e.elements.popper.querySelector(l),!l)||js(e.elements.popper,l)&&(e.elements.arrow=l))}const Bs={name:"arrow",enabled:!0,phase:"main",fn:MH,effect:pH,requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function c6(c){return c.split("-")[1]}var LH={top:"auto",right:"auto",bottom:"auto",left:"auto"};function gH(c){var e=c.x,t=c.y,s=window,l=s.devicePixelRatio||1;return{x:Q4(e*l)/l||0,y:Q4(t*l)/l||0}}function ze(c){var e,t=c.popper,s=c.popperRect,l=c.placement,n=c.variation,r=c.offsets,a=c.position,i=c.gpuAcceleration,o=c.adaptive,u=c.roundOffsets,C=c.isFixed,z=r.x,H=z===void 0?0:z,p=r.y,E=p===void 0?0:p,A=typeof u=="function"?u({x:H,y:E}):{x:H,y:E};H=A.x,E=A.y;var L=r.hasOwnProperty("x"),O=r.hasOwnProperty("y"),T=L2,_=p2,x=window;if(o){var K=a8(t),D="clientHeight",F="clientWidth";if(K===$2(t)&&(K=Q3(t),M3(K).position!=="static"&&a==="absolute"&&(D="scrollHeight",F="scrollWidth")),K=K,l===p2||(l===L2||l===k2)&&n===X4){_=E2;var X=C&&K===x&&x.visualViewport?x.visualViewport.height:K[D];E-=X-s.height,E*=i?1:-1}if(l===L2||(l===p2||l===E2)&&n===X4){T=k2;var B=C&&K===x&&x.visualViewport?x.visualViewport.width:K[F];H-=B-s.width,H*=i?1:-1}}var f1=Object.assign({position:a},o&&LH),c1=u===!0?gH({x:H,y:E}):{x:H,y:E};if(H=c1.x,E=c1.y,i){var V1;return Object.assign({},f1,(V1={},V1[_]=O?"0":"",V1[T]=L?"0":"",V1.transform=(x.devicePixelRatio||1)<=1?"translate("+H+"px, "+E+"px)":"translate3d("+H+"px, "+E+"px, 0)",V1))}return Object.assign({},f1,(e={},e[_]=O?E+"px":"",e[T]=L?H+"px":"",e.transform="",e))}function bH(c){var e=c.state,t=c.options,s=t.gpuAcceleration,l=s===void 0?!0:s,n=t.adaptive,r=n===void 0?!0:n,a=t.roundOffsets,i=a===void 0?!0:a,o={placement:t3(e.placement),variation:c6(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:l,isFixed:e.options.strategy==="fixed"};e.modifiersData.popperOffsets!=null&&(e.styles.popper=Object.assign({},e.styles.popper,ze(Object.assign({},o,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:i})))),e.modifiersData.arrow!=null&&(e.styles.arrow=Object.assign({},e.styles.arrow,ze(Object.assign({},o,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:i})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})}const Z7={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:bH,data:{}};var x8={passive:!0};function _H(c){var e=c.state,t=c.instance,s=c.options,l=s.scroll,n=l===void 0?!0:l,r=s.resize,a=r===void 0?!0:r,i=$2(e.elements.popper),o=[].concat(e.scrollParents.reference,e.scrollParents.popper);return n&&o.forEach(function(u){u.addEventListener("scroll",t.update,x8)}),a&&i.addEventListener("resize",t.update,x8),function(){n&&o.forEach(function(u){u.removeEventListener("scroll",t.update,x8)}),a&&i.removeEventListener("resize",t.update,x8)}}const Y7={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:_H,data:{}};var yH={left:"right",right:"left",bottom:"top",top:"bottom"};function Z8(c){return c.replace(/left|right|bottom|top/g,function(e){return yH[e]})}var SH={start:"end",end:"start"};function Ce(c){return c.replace(/start|end/g,function(e){return SH[e]})}function G7(c){var e=$2(c),t=e.pageXOffset,s=e.pageYOffset;return{scrollLeft:t,scrollTop:s}}function X7(c){return J4(Q3(c)).left+G7(c).scrollLeft}function wH(c, e){var t=$2(c),s=Q3(c),l=t.visualViewport,n=s.clientWidth,r=s.clientHeight,a=0,i=0;if(l){n=l.width,r=l.height;var o=Fs();(o||!o&&e==="fixed")&&(a=l.offsetLeft,i=l.offsetTop)}return{width:n,height:r,x:a+X7(c),y:i}}function EH(c){var e,t=Q3(c),s=G7(c),l=(e=c.ownerDocument)==null?void 0:e.body,n=v4(t.scrollWidth,t.clientWidth,l?l.scrollWidth:0,l?l.clientWidth:0),r=v4(t.scrollHeight,t.clientHeight,l?l.scrollHeight:0,l?l.clientHeight:0),a=-s.scrollLeft+X7(c),i=-s.scrollTop;return M3(l||t).direction==="rtl"&&(a+=v4(t.clientWidth,l?l.clientWidth:0)-n),{width:n,height:r,x:a,y:i}}function Q7(c){var e=M3(c),t=e.overflow,s=e.overflowX,l=e.overflowY;return/auto|scroll|overlay|hidden/.test(t+l+s)}function Ks(c){return["html","body","#document"].indexOf(n3(c))>=0?c.ownerDocument.body:x2(c)&&Q7(c)?c:Ks(w5(c))}function N6(c, e){var t;e===void 0&&(e=[]);var s=Ks(c),l=s===((t=c.ownerDocument)==null?void 0:t.body),n=$2(s),r=l?[n].concat(n.visualViewport||[],Q7(s)?s:[]):s,a=e.concat(r);return l?a:a.concat(N6(w5(r)))}function l7(c){return Object.assign({},c,{left:c.x,top:c.y,right:c.x+c.width,bottom:c.y+c.height})}function kH(c, e){var t=J4(c,!1,e==="fixed");return t.top=t.top+c.clientTop,t.left=t.left+c.clientLeft,t.bottom=t.top+c.clientHeight,t.right=t.left+c.clientWidth,t.width=c.clientWidth,t.height=c.clientHeight,t.x=t.left,t.y=t.top,t}function ve(c, e, t){return e===j7?l7(wH(c,t)):V4(e)?kH(e,t):l7(EH(Q3(c)))}function AH(c){var e=N6(w5(c)),t=["absolute","fixed"].indexOf(M3(c).position)>=0,s=t&&x2(c)?a8(c):c;return V4(s)?e.filter(function(l){return V4(l)&&js(l,s)&&n3(l)!=="body"}):[]}function PH(c, e, t, s){var l=e==="clippingParents"?AH(c):[].concat(e),n=[].concat(l,[t]),r=n[0],a=n.reduce(function(i, o){var u=ve(c,o,s);return i.top=v4(u.top,i.top),i.right=a5(u.right,i.right),i.bottom=a5(u.bottom,i.bottom),i.left=v4(u.left,i.left),i},ve(c,r,s));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}function Zs(c){var e=c.reference,t=c.element,s=c.placement,l=s?t3(s):null,n=s?c6(s):null,r=e.x+e.width/2-t.width/2,a=e.y+e.height/2-t.height/2,i;switch(l){case p2:i={x:r,y:e.y-t.height};break;case E2:i={x:r,y:e.y+e.height};break;case k2:i={x:e.x+e.width,y:a};break;case L2:i={x:e.x-t.width,y:a};break;default:i={x:e.x,y:e.y}}var o=l?K7(l):null;if(o!=null){var u=o==="y"?"height":"width";switch(n){case H4:i[o]=i[o]-(e[u]/2-t[u]/2);break;case X4:i[o]=i[o]+(e[u]/2-t[u]/2);break}}return i}function e6(c, e){e===void 0&&(e={});var t=e,s=t.placement,l=s===void 0?c.placement:s,n=t.strategy,r=n===void 0?c.strategy:n,a=t.boundary,i=a===void 0?Es:a,o=t.rootBoundary,u=o===void 0?j7:o,C=t.elementContext,z=C===void 0?A4:C,H=t.altBoundary,p=H===void 0?!1:H,E=t.padding,A=E===void 0?0:E,L=qs(typeof A!="number"?A:Ws(A,f6)),O=z===A4?ks:A4,T=c.rects.popper,_=c.elements[p?O:z],x=PH(V4(_)?_:_.contextElement||Q3(c.elements.popper),i,u,r),K=J4(c.elements.reference),D=Zs({reference:K,element:T,strategy:"absolute",placement:l}),F=l7(Object.assign({},T,D)),X=z===A4?F:K,B={top:x.top-X.top+L.top,bottom:X.bottom-x.bottom+L.bottom,left:x.left-X.left+L.left,right:X.right-x.right+L.right},f1=c.modifiersData.offset;if(z===A4&&f1){var c1=f1[l];Object.keys(B).forEach(function(V1){var m1=[k2,E2].indexOf(V1)>=0?1:-1,M1=[p2,E2].indexOf(V1)>=0?"y":"x";B[V1]+=c1[M1]*m1})}return B}function TH(c, e){e===void 0&&(e={});var t=e,s=t.placement,l=t.boundary,n=t.rootBoundary,r=t.padding,a=t.flipVariations,i=t.allowedAutoPlacements,o=i===void 0?U7:i,u=c6(s),C=u?a?t7:t7.filter(function(p){return c6(p)===u}):f6,z=C.filter(function(p){return o.indexOf(p)>=0});z.length===0&&(z=C);var H=z.reduce(function(p, E){return p[E]=e6(c,{placement:E,boundary:l,rootBoundary:n,padding:r})[t3(E)],p},{});return Object.keys(H).sort(function(p, E){return H[p]-H[E]})}function OH(c){if(t3(c)===S5)return[];var e=Z8(c);return[Ce(c),e,Ce(e)]}function xH(c){var e=c.state,t=c.options,s=c.name;if(!e.modifiersData[s]._skip){for(var l=t.mainAxis,n=l===void 0?!0:l,r=t.altAxis,a=r===void 0?!0:r,i=t.fallbackPlacements,o=t.padding,u=t.boundary,C=t.rootBoundary,z=t.altBoundary,H=t.flipVariations,p=H===void 0?!0:H,E=t.allowedAutoPlacements,A=e.options.placement,L=t3(A),O=L===A,T=i||(O||!p?[Z8(A)]:OH(A)),_=[A].concat(T).reduce(function(U, S){return U.concat(t3(S)===S5?TH(e,{placement:S,boundary:u,rootBoundary:C,padding:o,flipVariations:p,allowedAutoPlacements:E}):S)},[]),x=e.rects.reference,K=e.rects.popper,D=new Map,F=!0,X=_[0],B=0; B<_.length; B++){var f1=_[B],c1=t3(f1),V1=c6(f1)===H4,m1=[p2,E2].indexOf(c1)>=0,M1=m1?"width":"height",z1=e6(e,{placement:f1,boundary:u,rootBoundary:C,altBoundary:z,padding:o}),n1=m1?V1?k2:L2:V1?E2:p2;x[M1]>K[M1]&&(n1=Z8(n1));var v1=Z8(n1),T1=[];if(n&&T1.push(z1[c1]<=0),a&&T1.push(z1[n1]<=0,z1[v1]<=0),T1.every(function(U){return U})){X=f1,F=!1;break}D.set(f1,T1)}if(F)for(var I1=p?3:1,A1=function(S){var Y=_.find(function(s1){var i1=D.get(s1);if(i1)return i1.slice(0,S).every(function(_1){return _1})});if(Y)return X=Y,"break"},k=I1; k>0; k--){var q=A1(k);if(q==="break")break}e.placement!==X&&(e.modifiersData[s]._skip=!0,e.placement=X,e.reset=!0)}}const Ys={name:"flip",enabled:!0,phase:"main",fn:xH,requiresIfExists:["offset"],data:{_skip:!1}};function He(c, e, t){return t===void 0&&(t={x:0,y:0}),{top:c.top-e.height-t.y,right:c.right-e.width+t.x,bottom:c.bottom-e.height+t.y,left:c.left-e.width-t.x}}function Ve(c){return[p2,k2,E2,L2].some(function(e){return c[e]>=0})}function IH(c){var e=c.state,t=c.name,s=e.rects.reference,l=e.rects.popper,n=e.modifiersData.preventOverflow,r=e6(e,{elementContext:"reference"}),a=e6(e,{altBoundary:!0}),i=He(r,s),o=He(a,l,n),u=Ve(i),C=Ve(o);e.modifiersData[t]={referenceClippingOffsets:i,popperEscapeOffsets:o,isReferenceHidden:u,hasPopperEscaped:C},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":u,"data-popper-escaped":C})}const Gs={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:IH};function $H(c, e, t){var s=t3(c),l=[L2,p2].indexOf(s)>=0?-1:1,n=typeof t=="function"?t(Object.assign({},e,{placement:c})):t,r=n[0],a=n[1];return r=r||0,a=(a||0)*l,[L2,k2].indexOf(s)>=0?{x:a,y:r}:{x:r,y:a}}function NH(c){var e=c.state,t=c.options,s=c.name,l=t.offset,n=l===void 0?[0,0]:l,r=U7.reduce(function(u, C){return u[C]=$H(C,e.rects,n),u},{}),a=r[e.placement],i=a.x,o=a.y;e.modifiersData.popperOffsets!=null&&(e.modifiersData.popperOffsets.x+=i,e.modifiersData.popperOffsets.y+=o),e.modifiersData[s]=r}const Xs={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:NH};function DH(c){var e=c.state,t=c.name;e.modifiersData[t]=Zs({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})}const J7={name:"popperOffsets",enabled:!0,phase:"read",fn:DH,data:{}};function RH(c){return c==="x"?"y":"x"}function FH(c){var e=c.state,t=c.options,s=c.name,l=t.mainAxis,n=l===void 0?!0:l,r=t.altAxis,a=r===void 0?!1:r,i=t.boundary,o=t.rootBoundary,u=t.altBoundary,C=t.padding,z=t.tether,H=z===void 0?!0:z,p=t.tetherOffset,E=p===void 0?0:p,A=e6(e,{boundary:i,rootBoundary:o,padding:C,altBoundary:u}),L=t3(e.placement),O=c6(e.placement),T=!O,_=K7(L),x=RH(_),K=e.modifiersData.popperOffsets,D=e.rects.reference,F=e.rects.popper,X=typeof E=="function"?E(Object.assign({},e.rects,{placement:e.placement})):E,B=typeof X=="number"?{mainAxis:X,altAxis:X}:Object.assign({mainAxis:0,altAxis:0},X),f1=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,c1={x:0,y:0};if(K){if(n){var V1,m1=_==="y"?p2:L2,M1=_==="y"?E2:k2,z1=_==="y"?"height":"width",n1=K[_],v1=n1+A[m1],T1=n1-A[M1],I1=H?-F[z1]/2:0,A1=O===H4?D[z1]:F[z1],k=O===H4?-F[z1]:-D[z1],q=e.elements.arrow,U=H&&q?B7(q):{width:0,height:0},S=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:Us(),Y=S[m1],s1=S[M1],i1=$6(0,D[z1],U[z1]),_1=T?D[z1]/2-I1-i1-Y-B.mainAxis:A1-i1-Y-B.mainAxis,D1=T?-D[z1]/2+I1+i1+s1+B.mainAxis:k+i1+s1+B.mainAxis,g=e.elements.arrow&&a8(e.elements.arrow),h=g?_==="y"?g.clientTop||0:g.clientLeft||0:0,V=(V1=f1==null?void 0:f1[_])!=null?V1:0,b=n1+_1-V-h,P=n1+D1-V,R=$6(H?a5(v1,b):v1,n1,H?v4(T1,P):T1);K[_]=R,c1[_]=R-n1}if(a){var G,l1=_==="x"?p2:L2,e1=_==="x"?E2:k2,t1=K[x],w=x==="y"?"height":"width",j=t1+A[l1],r1=t1-A[e1],a1=[p2,L2].indexOf(L)!==-1,p1=(G=f1==null?void 0:f1[x])!=null?G:0,y1=a1?j:t1-D[w]-F[w]-p1+B.altAxis,P1=a1?t1+D[w]+F[w]-p1-B.altAxis:r1,O1=H&&a1?HH(y1,t1,P1):$6(H?y1:j,t1,H?P1:r1);K[x]=O1,c1[x]=O1-t1}e.modifiersData[s]=c1}}const Qs={name:"preventOverflow",enabled:!0,phase:"main",fn:FH,requiresIfExists:["offset"]};function jH(c){return{scrollLeft:c.scrollLeft,scrollTop:c.scrollTop}}function UH(c){return c===$2(c)||!x2(c)?G7(c):jH(c)}function qH(c){var e=c.getBoundingClientRect(),t=Q4(e.width)/c.offsetWidth||1,s=Q4(e.height)/c.offsetHeight||1;return t!==1||s!==1}function WH(c, e, t){t===void 0&&(t=!1);var s=x2(e),l=x2(e)&&qH(e),n=Q3(e),r=J4(c,l,t),a={scrollLeft:0,scrollTop:0},i={x:0,y:0};return(s||!s&&!t)&&((n3(e)!=="body"||Q7(n))&&(a=UH(e)),x2(e)?(i=J4(e,!0),i.x+=e.clientLeft,i.y+=e.clientTop):n&&(i.x=X7(n))),{x:r.left+a.scrollLeft-i.x,y:r.top+a.scrollTop-i.y,width:r.width,height:r.height}}function BH(c){var e=new Map,t=new Set,s=[];c.forEach(function(n){e.set(n.name,n)});function l(n){t.add(n.name);var r=[].concat(n.requires||[],n.requiresIfExists||[]);r.forEach(function(a){if(!t.has(a)){var i=e.get(a);i&&l(i)}}),s.push(n)}return c.forEach(function(n){t.has(n.name)||l(n)}),s}function KH(c){var e=BH(c);return Rs.reduce(function(t, s){return t.concat(e.filter(function(l){return l.phase===s}))},[])}function ZH(c){var e;return function(){return e||(e=new Promise(function(t){Promise.resolve().then(function(){e=void 0,t(c())})})),e}}function YH(c){var e=c.reduce(function(t, s){var l=t[s.name];return t[s.name]=l?Object.assign({},l,s,{options:Object.assign({},l.options,s.options),data:Object.assign({},l.data,s.data)}):s,t},{});return Object.keys(e).map(function(t){return e[t]})}var Me={placement:"bottom",modifiers:[],strategy:"absolute"};function pe(){for(var c=arguments.length,e=new Array(c),t=0; t 0 || newTransmitted > 0): + return lastHandshake + // session never received bytes -> first receive + case oldStats.BytesReceived == 0 && newReceived > 0 && (oldStats.LastHandshake == nil || oldStats.LastHandshake.Before(oldestHandshakeTime)): + return lastHandshake + // session never transmitted bytes -> first transmit + case oldStats.BytesTransmitted == 0 && newTransmitted > 0 && (oldStats.LastSessionStart == nil || oldStats.LastHandshake.Before(oldestHandshakeTime)): + return lastHandshake + // session restarted as newer send or transmit counts are lower + case (newReceived != 0 && newReceived < oldStats.BytesReceived) || (newTransmitted != 0 && newTransmitted < oldStats.BytesTransmitted): + return lastHandshake + default: + return oldStats.LastSessionStart + } +} + +func (c *StatisticsCollector) startPingWorkers(ctx context.Context) { + if !c.cfg.Statistics.UsePingChecks { + return + } + + if c.pingJobs != nil { + return // already started + } + + c.pingWaitGroup = sync.WaitGroup{} + c.pingWaitGroup.Add(c.cfg.Statistics.PingCheckWorkers) + c.pingJobs = make(chan domain.Peer, c.cfg.Statistics.PingCheckWorkers) + + // start workers + for i := 0; i < c.cfg.Statistics.PingCheckWorkers; i++ { + go c.pingWorker(ctx) + } + + // start cleanup goroutine + go func() { + c.pingWaitGroup.Wait() + + logrus.Tracef("stopped ping checks") + }() + + go c.enqueuePingChecks(ctx) + + logrus.Tracef("started ping checks") +} + +func (c *StatisticsCollector) enqueuePingChecks(ctx context.Context) { + // Start ticker + ticker := time.NewTicker(c.cfg.Statistics.PingCheckInterval) + defer ticker.Stop() + defer close(c.pingJobs) + + for { + select { + case <-ctx.Done(): + return // program stopped + case <-ticker.C: + interfaces, err := c.db.GetAllInterfaces(ctx) + if err != nil { + logrus.Warnf("failed to fetch all interfaces for ping checks: %v", err) + continue + } + + for _, in := range interfaces { + peers, err := c.db.GetInterfacePeers(ctx, in.Identifier) + if err != nil { + logrus.Warnf("failed to fetch peers for ping checks (interface %s): %v", in.Identifier, err) + continue + } + for _, peer := range peers { + c.pingJobs <- peer + } + } + } + } +} + +func (c *StatisticsCollector) pingWorker(ctx context.Context) { + defer c.pingWaitGroup.Done() + for peer := range c.pingJobs { + peerPingable := c.isPeerPingable(ctx, peer) + logrus.Tracef("peer %s pingable: %t", peer.Identifier, peerPingable) + } +} + +func (c *StatisticsCollector) isPeerPingable(ctx context.Context, peer domain.Peer) bool { + if c.cfg.Statistics.UsePingChecks == false { + return false + } + + checkAddr := peer.CheckAliveAddress() + if checkAddr == "" { + return false + } + + pinger, err := probing.NewPinger(checkAddr) + if err != nil { + logrus.Tracef("failed to instatiate pinger for %s: %v", checkAddr, err) + return false + } + + checkCount := 1 + pinger.SetPrivileged(!c.cfg.Statistics.PingUnprivileged) + pinger.Count = checkCount + pinger.Timeout = 2 * time.Second + err = pinger.RunWithContext(ctx) // Blocks until finished. + if err != nil { + logrus.Tracef("pinger for %s exited unexpectedly: %v", checkAddr, err) + return false + } + stats := pinger.Statistics() + return stats.PacketsRecv == checkCount +} diff --git a/internal/app/wireguard/statistics_test.go b/internal/app/wireguard/statistics_test.go new file mode 100644 index 0000000..25b10f1 --- /dev/null +++ b/internal/app/wireguard/statistics_test.go @@ -0,0 +1,124 @@ +package wireguard + +import ( + "github.com/h44z/wg-portal/internal/domain" + "reflect" + "testing" + "time" +) + +func Test_getSessionStartTime(t *testing.T) { + now := time.Now() + nowMinus1 := now.Add(-1 * time.Minute) + nowMinus3 := now.Add(-3 * time.Minute) + nowMinus5 := now.Add(-5 * time.Minute) + + type args struct { + oldStats domain.PeerStatus + newReceived uint64 + newTransmitted uint64 + lastHandshake *time.Time + } + tests := []struct { + name string + args args + want *time.Time + }{ + { + name: "not connected", + args: args{ + newReceived: 0, + newTransmitted: 0, + lastHandshake: nil, + }, + want: nil, + }, + { + name: "freshly connected", + args: args{ + oldStats: domain.PeerStatus{LastSessionStart: &nowMinus1}, + newReceived: 100, + newTransmitted: 100, + lastHandshake: &now, + }, + want: &now, + }, + { + name: "freshly connected (no prev session)", + args: args{ + oldStats: domain.PeerStatus{LastSessionStart: nil}, + newReceived: 100, + newTransmitted: 100, + lastHandshake: &now, + }, + want: &now, + }, + { + name: "still connected", + args: args{ + oldStats: domain.PeerStatus{LastSessionStart: &nowMinus1, BytesReceived: 10, BytesTransmitted: 10}, + newReceived: 100, + newTransmitted: 100, + lastHandshake: &now, + }, + want: &nowMinus1, + }, + { + name: "no longer connected", + args: args{ + oldStats: domain.PeerStatus{LastSessionStart: &nowMinus5, BytesReceived: 100, BytesTransmitted: 100}, + newReceived: 100, + newTransmitted: 100, + lastHandshake: &nowMinus3, + }, + want: &nowMinus5, + }, + { + name: "reconnect (recv, hs outdated)", + args: args{ + oldStats: domain.PeerStatus{LastHandshake: &nowMinus5, BytesReceived: 100, BytesTransmitted: 100}, + newReceived: 10, + newTransmitted: 100, + lastHandshake: &nowMinus1, + }, + want: &nowMinus1, + }, + { + name: "reconnect (recv)", + args: args{ + oldStats: domain.PeerStatus{LastHandshake: &nowMinus1, BytesReceived: 100, BytesTransmitted: 100}, + newReceived: 10, + newTransmitted: 100, + lastHandshake: &now, + }, + want: &now, + }, + { + name: "reconnect (sent, hs outdated)", + args: args{ + oldStats: domain.PeerStatus{LastHandshake: &nowMinus5, BytesReceived: 100, BytesTransmitted: 100}, + newReceived: 100, + newTransmitted: 10, + lastHandshake: &nowMinus1, + }, + want: &nowMinus1, + }, + { + name: "reconnect (sent)", + args: args{ + oldStats: domain.PeerStatus{LastSessionStart: &nowMinus1, BytesReceived: 100, BytesTransmitted: 100}, + newReceived: 100, + newTransmitted: 10, + lastHandshake: &now, + }, + want: &now, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getSessionStartTime(tt.args.oldStats, tt.args.newReceived, tt.args.newTransmitted, tt.args.lastHandshake); !reflect.DeepEqual(got, tt.want) { + t.Errorf("getSessionStartTime() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/app/wireguard.go b/internal/app/wireguard/wireguard.go similarity index 76% rename from internal/app/wireguard.go rename to internal/app/wireguard/wireguard.go index 495ce87..4559a76 100644 --- a/internal/app/wireguard.go +++ b/internal/app/wireguard/wireguard.go @@ -1,9 +1,10 @@ -package app +package wireguard import ( "context" "errors" "fmt" + "github.com/h44z/wg-portal/internal/app" "time" "github.com/h44z/wg-portal/internal" @@ -15,39 +16,19 @@ import ( "github.com/h44z/wg-portal/internal/domain" ) -// region local-dependencies - -type wireGuardDatabaseRepo interface { - GetInterface(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, error) - GetInterfaceAndPeers(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, []domain.Peer, error) - GetAllInterfaces(ctx context.Context) ([]domain.Interface, error) - FindInterfaces(ctx context.Context, search string) ([]domain.Interface, error) - GetInterfaceIps(ctx context.Context) (map[domain.InterfaceIdentifier][]domain.Cidr, error) - SaveInterface(ctx context.Context, id domain.InterfaceIdentifier, updateFunc func(in *domain.Interface) (*domain.Interface, error)) error - DeleteInterface(ctx context.Context, id domain.InterfaceIdentifier) error - GetInterfacePeers(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.Peer, error) - FindInterfacePeers(ctx context.Context, id domain.InterfaceIdentifier, search string) ([]domain.Peer, error) - GetUserPeers(ctx context.Context, id domain.UserIdentifier) ([]domain.Peer, error) - FindUserPeers(ctx context.Context, id domain.UserIdentifier, search string) ([]domain.Peer, error) - SavePeer(ctx context.Context, id domain.PeerIdentifier, updateFunc func(in *domain.Peer) (*domain.Peer, error)) error - DeletePeer(ctx context.Context, id domain.PeerIdentifier) error -} - -// endregion local-dependencies - -type wireGuardManager struct { +type Manager struct { cfg *config.Config bus evbus.MessageBus - db wireGuardDatabaseRepo - wg wireGuardRepo + db InterfaceAndPeerDatabaseRepo + wg InterfaceController } -func newWireGuardManager(cfg *config.Config, bus evbus.MessageBus, wgRepo wireGuardRepo, db wireGuardDatabaseRepo) (*wireGuardManager, error) { - m := &wireGuardManager{ +func NewWireGuardManager(cfg *config.Config, bus evbus.MessageBus, wg InterfaceController, db InterfaceAndPeerDatabaseRepo) (*Manager, error) { + m := &Manager{ cfg: cfg, bus: bus, - wg: wgRepo, + wg: wg, db: db, } @@ -56,11 +37,11 @@ func newWireGuardManager(cfg *config.Config, bus evbus.MessageBus, wgRepo wireGu return m, nil } -func (m wireGuardManager) connectToMessageBus() { - _ = m.bus.Subscribe(TopicUserCreated, m.handleUserCreationEvent) +func (m Manager) connectToMessageBus() { + _ = m.bus.Subscribe(app.TopicUserCreated, m.handleUserCreationEvent) } -func (m wireGuardManager) handleUserCreationEvent(user *domain.User) { +func (m Manager) handleUserCreationEvent(user *domain.User) { logrus.Errorf("Handling new user event for %s", user.Identifier) err := m.CreateDefaultPeer(context.Background(), user) @@ -70,7 +51,7 @@ func (m wireGuardManager) handleUserCreationEvent(user *domain.User) { } } -func (m wireGuardManager) GetImportableInterfaces(ctx context.Context) ([]domain.PhysicalInterface, error) { +func (m Manager) GetImportableInterfaces(ctx context.Context) ([]domain.PhysicalInterface, error) { physicalInterfaces, err := m.wg.GetInterfaces(ctx) if err != nil { return nil, err @@ -79,7 +60,7 @@ func (m wireGuardManager) GetImportableInterfaces(ctx context.Context) ([]domain return physicalInterfaces, nil } -func (m wireGuardManager) ImportNewInterfaces(ctx context.Context, filter ...domain.InterfaceIdentifier) error { +func (m Manager) ImportNewInterfaces(ctx context.Context, filter ...domain.InterfaceIdentifier) error { physicalInterfaces, err := m.wg.GetInterfaces(ctx) if err != nil { return err @@ -124,7 +105,7 @@ func (m wireGuardManager) ImportNewInterfaces(ctx context.Context, filter ...dom return nil } -func (m wireGuardManager) importInterface(ctx context.Context, in *domain.PhysicalInterface, peers []domain.PhysicalPeer) error { +func (m Manager) importInterface(ctx context.Context, in *domain.PhysicalInterface, peers []domain.PhysicalPeer) error { now := time.Now() iface := domain.ConvertPhysicalInterface(in) iface.BaseModel = domain.BaseModel{ @@ -161,7 +142,7 @@ func (m wireGuardManager) importInterface(ctx context.Context, in *domain.Physic return nil } -func (m wireGuardManager) importPeer(ctx context.Context, in *domain.Interface, p *domain.PhysicalPeer) error { +func (m Manager) importPeer(ctx context.Context, in *domain.Interface, p *domain.PhysicalPeer) error { now := time.Now() peer := domain.ConvertPhysicalPeer(p) peer.BaseModel = domain.BaseModel{ @@ -207,7 +188,7 @@ func (m wireGuardManager) importPeer(ctx context.Context, in *domain.Interface, return nil } -func (m wireGuardManager) RestoreInterfaceState(ctx context.Context, updateDbOnError bool, filter ...domain.InterfaceIdentifier) error { +func (m Manager) RestoreInterfaceState(ctx context.Context, updateDbOnError bool, filter ...domain.InterfaceIdentifier) error { interfaces, err := m.db.GetAllInterfaces(ctx) if err != nil { return err @@ -286,24 +267,24 @@ func (m wireGuardManager) RestoreInterfaceState(ctx context.Context, updateDbOnE return nil } -func (m wireGuardManager) CreateDefaultPeer(ctx context.Context, user *domain.User) error { +func (m Manager) CreateDefaultPeer(ctx context.Context, user *domain.User) error { // TODO: implement return nil } -func (m wireGuardManager) GetInterfaceAndPeers(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, []domain.Peer, error) { +func (m Manager) GetInterfaceAndPeers(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, []domain.Peer, error) { return m.db.GetInterfaceAndPeers(ctx, id) } -func (m wireGuardManager) GetAllInterfaces(ctx context.Context) ([]domain.Interface, error) { +func (m Manager) GetAllInterfaces(ctx context.Context) ([]domain.Interface, error) { return m.db.GetAllInterfaces(ctx) } -func (m wireGuardManager) GetUserPeers(ctx context.Context, id domain.UserIdentifier) ([]domain.Peer, error) { +func (m Manager) GetUserPeers(ctx context.Context, id domain.UserIdentifier) ([]domain.Peer, error) { return m.db.GetUserPeers(ctx, id) } -func (m wireGuardManager) PrepareInterface(ctx context.Context) (*domain.Interface, error) { +func (m Manager) PrepareInterface(ctx context.Context) (*domain.Interface, error) { currentUser := domain.GetUserInfo(ctx) kp, err := domain.NewFreshKeypair() @@ -321,6 +302,16 @@ func (m wireGuardManager) PrepareInterface(ctx context.Context) (*domain.Interfa return nil, fmt.Errorf("failed to generate new ip config: %w", err) } + port, err := m.getFreshListenPort(ctx) + if err != nil { + return nil, fmt.Errorf("failed to generate new listen port: %w", err) + } + + ips := []domain.Cidr{ipv4} + if m.cfg.Advanced.UseIpV6 { + ips = append(ips, ipv6) + } + freshInterface := &domain.Interface{ BaseModel: domain.BaseModel{ CreatedBy: string(currentUser.Id), @@ -330,8 +321,8 @@ func (m wireGuardManager) PrepareInterface(ctx context.Context) (*domain.Interfa }, Identifier: id, KeyPair: kp, - ListenPort: 0, // TODO - Addresses: []domain.Cidr{ipv4, ipv6}, + ListenPort: port, + Addresses: ips, DnsStr: "", DnsSearchStr: "", Mtu: 1420, @@ -365,7 +356,7 @@ func (m wireGuardManager) PrepareInterface(ctx context.Context) (*domain.Interfa return freshInterface, nil } -func (m wireGuardManager) getNewInterfaceName(ctx context.Context) (domain.InterfaceIdentifier, error) { +func (m Manager) getNewInterfaceName(ctx context.Context) (domain.InterfaceIdentifier, error) { namePrefix := "wg" nameSuffix := 1 @@ -394,15 +385,16 @@ func (m wireGuardManager) getNewInterfaceName(ctx context.Context) (domain.Inter return name, nil } -func (m wireGuardManager) getFreshIpConfig(ctx context.Context) (ipV4, ipV6 domain.Cidr, err error) { +func (m Manager) getFreshIpConfig(ctx context.Context) (ipV4, ipV6 domain.Cidr, err error) { ips, err := m.db.GetInterfaceIps(ctx) if err != nil { err = fmt.Errorf("failed to get existing IP addresses: %w", err) return } - ipV4, _ = domain.CidrFromString("10.6.6.1/24") - ipV6, _ = domain.CidrFromString("fdfd:d3ad:c0de:1234::1/64") + useV6 := m.cfg.Advanced.UseIpV6 + ipV4, _ = domain.CidrFromString(m.cfg.Advanced.StartCidrV4) + ipV6, _ = domain.CidrFromString(m.cfg.Advanced.StartCidrV6) for { ipV4Conflict := false @@ -419,7 +411,7 @@ func (m wireGuardManager) getFreshIpConfig(ctx context.Context) (ipV4, ipV6 doma } } - if !ipV4Conflict && !ipV6Conflict { + if !ipV4Conflict && (!useV6 || !ipV6Conflict) { break } @@ -427,7 +419,7 @@ func (m wireGuardManager) getFreshIpConfig(ctx context.Context) (ipV4, ipV6 doma ipV4 = ipV4.NextSubnet() } - if ipV6Conflict { + if ipV6Conflict && useV6 { ipV6 = ipV6.NextSubnet() } } @@ -435,7 +427,37 @@ func (m wireGuardManager) getFreshIpConfig(ctx context.Context) (ipV4, ipV6 doma return } -func (m wireGuardManager) CreateInterface(ctx context.Context, in *domain.Interface) (*domain.Interface, error) { +func (m Manager) getFreshListenPort(ctx context.Context) (port int, err error) { + existingInterfaces, err := m.db.GetAllInterfaces(ctx) + if err != nil { + return -1, err + } + + port = m.cfg.Advanced.StartListenPort + + for { + conflict := false + for _, in := range existingInterfaces { + if in.ListenPort == port { + conflict = true + break + } + } + if !conflict { + break + } + + port++ + } + + if port > 65535 { // maximum allowed port number (16 bit uint) + return -1, fmt.Errorf("port space exhausted") + } + + return +} + +func (m Manager) CreateInterface(ctx context.Context, in *domain.Interface) (*domain.Interface, error) { existingInterface, err := m.db.GetInterface(ctx, in.Identifier) if err != nil && !errors.Is(err, domain.ErrNotFound) { return nil, fmt.Errorf("unable to load existing interface %s: %w", in.Identifier, err) @@ -468,7 +490,7 @@ func (m wireGuardManager) CreateInterface(ctx context.Context, in *domain.Interf return in, nil } -func (m wireGuardManager) UpdateInterface(ctx context.Context, in *domain.Interface) (*domain.Interface, error) { +func (m Manager) UpdateInterface(ctx context.Context, in *domain.Interface) (*domain.Interface, error) { existingInterface, err := m.db.GetInterface(ctx, in.Identifier) if err != nil { return nil, fmt.Errorf("unable to load existing interface %s: %w", in.Identifier, err) @@ -498,7 +520,7 @@ func (m wireGuardManager) UpdateInterface(ctx context.Context, in *domain.Interf return in, nil } -func (m wireGuardManager) validateModifications(ctx context.Context, old, new *domain.Interface) error { +func (m Manager) validateModifications(ctx context.Context, old, new *domain.Interface) error { currentUser := domain.GetUserInfo(ctx) if !currentUser.IsAdmin { @@ -508,7 +530,7 @@ func (m wireGuardManager) validateModifications(ctx context.Context, old, new *d return nil } -func (m wireGuardManager) validateCreation(ctx context.Context, old, new *domain.Interface) error { +func (m Manager) validateCreation(ctx context.Context, old, new *domain.Interface) error { currentUser := domain.GetUserInfo(ctx) if new.Identifier == "" { diff --git a/internal/config/config.go b/internal/config/config.go index 9603cd3..477664a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -26,8 +26,22 @@ type Config struct { LogLevel string `yaml:"log_level"` StartupTimeout time.Duration `yaml:"startup_timeout"` LdapSyncInterval time.Duration `yaml:"ldap_sync_interval"` + StartListenPort int `yaml:"start_listen_port"` + StartCidrV4 string `yaml:"start_cidr_v4"` + StartCidrV6 string `yaml:"start_cidr_v6"` + UseIpV6 bool `yaml:"use_ip_v6"` } `yaml:"advanced"` + Statistics struct { + UsePingChecks bool `yaml:"use_ping_checks"` + PingCheckWorkers int `yaml:"ping_check_workers"` + PingUnprivileged bool `yaml:"ping_unprivileged"` + PingCheckInterval time.Duration `yaml:"ping_check_interval"` + CollectInterfaceData bool `yaml:"collect_interface_data"` + CollectPeerData bool `yaml:"collect_peer_data"` + DataCollectionInterval time.Duration `yaml:"data_collection_interval"` + } + Mail MailConfig `yaml:"mail"` Auth Auth `yaml:"auth"` @@ -37,11 +51,9 @@ type Config struct { Web WebConfig `yaml:"web"` } -func GetConfig() (*Config, error) { +func defaultConfig() *Config { cfg := &Config{} - // default config - cfg.Core.ImportExisting = true cfg.Core.RestoreState = true @@ -51,6 +63,7 @@ func GetConfig() (*Config, error) { } cfg.Web = WebConfig{ + RequestLogging: false, ListeningAddress: ":8888", SessionSecret: "verysecret", SessionIdentifier: "wgPortalSession", @@ -58,6 +71,25 @@ func GetConfig() (*Config, error) { cfg.Auth.CallbackUrlPrefix = "/api/v0" + cfg.Advanced.StartListenPort = 51820 + cfg.Advanced.StartCidrV4 = "10.6.6.1/24" + cfg.Advanced.StartCidrV6 = "fdfd:d3ad:c0de:1234::1/64" + cfg.Advanced.UseIpV6 = true + + cfg.Statistics.UsePingChecks = true + cfg.Statistics.PingCheckWorkers = 10 + cfg.Statistics.PingUnprivileged = false + cfg.Statistics.PingCheckInterval = 1 * time.Minute + cfg.Statistics.CollectInterfaceData = true + cfg.Statistics.CollectPeerData = true + cfg.Statistics.DataCollectionInterval = 10 * time.Second + + return cfg +} + +func GetConfig() (*Config, error) { + cfg := defaultConfig() + // override config values from YAML file cfgFileName := "config.yml" diff --git a/internal/config/database.go b/internal/config/database.go index 1bed851..722a995 100644 --- a/internal/config/database.go +++ b/internal/config/database.go @@ -1,5 +1,7 @@ package config +import "time" + type SupportedDatabase string const ( @@ -10,6 +12,8 @@ const ( ) type DatabaseConfig struct { - Type SupportedDatabase `yaml:"type"` - DSN string `yaml:"dsn"` // On SQLite: the database file-path, otherwise the dsn (see: https://gorm.io/docs/connecting_to_the_database.html) + Debug bool `yaml:"debug"` + SlowQueryThreshold time.Duration `yaml:"slow_query_threshold"` // 0 means no logging of slow queries + Type SupportedDatabase `yaml:"type"` + DSN string `yaml:"dsn"` // On SQLite: the database file-path, otherwise the dsn (see: https://gorm.io/docs/connecting_to_the_database.html) } diff --git a/internal/config/web.go b/internal/config/web.go index 00f9b58..5a8ed85 100644 --- a/internal/config/web.go +++ b/internal/config/web.go @@ -1,6 +1,7 @@ package config type WebConfig struct { + RequestLogging bool `yaml:"request_logging"` ExternalUrl string `yaml:"external_url"` ListeningAddress string `yaml:"listening_address"` SessionIdentifier string `yaml:"session_identifier"` diff --git a/internal/domain/peer.go b/internal/domain/peer.go index acdbb6d..2a27c2b 100644 --- a/internal/domain/peer.go +++ b/internal/domain/peer.go @@ -54,17 +54,30 @@ func (p Peer) IsDisabled() bool { return p.Disabled != nil } +func (p Peer) CheckAliveAddress() string { + if p.Interface.CheckAliveAddress != "" { + return p.Interface.CheckAliveAddress + } + + if len(p.Interface.Addresses) > 0 { + return p.Interface.Addresses[0].Addr // take the first peer address + } + + return "" +} + type PeerInterfaceConfig struct { KeyPair // private/public Key of the peer Type InterfaceType `gorm:"column:iface_type"` // the interface type (server, client, any) - Addresses []Cidr `gorm:"many2many:peer_addresses;"` // the interface ip addresses - DnsStr StringConfigOption `gorm:"embedded;embeddedPrefix:iface_dns_str_"` // the dns server that should be set if the interface is up, comma separated - DnsSearchStr StringConfigOption `gorm:"embedded;embeddedPrefix:iface_dns_search_str_"` // the dns search option string that should be set if the interface is up, will be appended to DnsStr - Mtu IntConfigOption `gorm:"embedded;embeddedPrefix:iface_mtu_"` // the device MTU - FirewallMark Int32ConfigOption `gorm:"embedded;embeddedPrefix:iface_firewall_mark_"` // a firewall mark - RoutingTable StringConfigOption `gorm:"embedded;embeddedPrefix:iface_routing_table_"` // the routing table + Addresses []Cidr `gorm:"many2many:peer_addresses;"` // the interface ip addresses + CheckAliveAddress string `gorm:"column:check_alive_address"` // optional ip address or DNS name that is used for ping checks + DnsStr StringConfigOption `gorm:"embedded;embeddedPrefix:iface_dns_str_"` // the dns server that should be set if the interface is up, comma separated + DnsSearchStr StringConfigOption `gorm:"embedded;embeddedPrefix:iface_dns_search_str_"` // the dns search option string that should be set if the interface is up, will be appended to DnsStr + Mtu IntConfigOption `gorm:"embedded;embeddedPrefix:iface_mtu_"` // the device MTU + FirewallMark Int32ConfigOption `gorm:"embedded;embeddedPrefix:iface_firewall_mark_"` // a firewall mark + RoutingTable StringConfigOption `gorm:"embedded;embeddedPrefix:iface_routing_table_"` // the routing table PreUp StringConfigOption `gorm:"embedded;embeddedPrefix:iface_pre_up_"` // action that is executed before the device is up PostUp StringConfigOption `gorm:"embedded;embeddedPrefix:iface_post_up_"` // action that is executed after the device is up @@ -88,8 +101,8 @@ type PhysicalPeer struct { LastHandshake time.Time ProtocolVersion int - BytesUpload uint64 - BytesDownload uint64 + BytesUpload uint64 // upload bytes are the number of bytes that the remote peer has sent to the server + BytesDownload uint64 // upload bytes are the number of bytes that the remote peer has received from the server } func (p PhysicalPeer) GetPresharedKey() *wgtypes.Key { diff --git a/internal/domain/statistics.go b/internal/domain/statistics.go new file mode 100644 index 0000000..c21bc29 --- /dev/null +++ b/internal/domain/statistics.go @@ -0,0 +1,26 @@ +package domain + +import "time" + +type PeerStatus struct { + PeerId PeerIdentifier `gorm:"primaryKey;column:identifier"` + UpdatedAt time.Time `gorm:"column:updated_at"` + + IsPingable bool `gorm:"column:pingable"` + LastPing *time.Time `gorm:"column:last_ping"` + + BytesReceived uint64 `gorm:"column:received"` + BytesTransmitted uint64 `gorm:"column:transmitted"` + + LastHandshake *time.Time `gorm:"column:last_handshake"` + Endpoint string `gorm:"column:endpoint"` + LastSessionStart *time.Time `gorm:"column:last_session_start"` +} + +type InterfaceStatus struct { + InterfaceId InterfaceIdentifier `gorm:"primaryKey;column:identifier"` + UpdatedAt time.Time `gorm:"column:updated_at"` + + BytesReceived uint64 `gorm:"column:received"` + BytesTransmitted uint64 `gorm:"column:transmitted"` +} diff --git a/internal/app/ldap_utils.go b/internal/ldap_utils.go similarity index 78% rename from internal/app/ldap_utils.go rename to internal/ldap_utils.go index 07e14c1..0abad23 100644 --- a/internal/app/ldap_utils.go +++ b/internal/ldap_utils.go @@ -1,21 +1,19 @@ -package app +package internal import ( "crypto/tls" "fmt" "os" - "github.com/h44z/wg-portal/internal" - "github.com/go-ldap/ldap/v3" "github.com/h44z/wg-portal/internal/config" ) -type rawLdapUser map[string]interface{} +type RawLdapUser map[string]any -func ldapFindAllUsers(conn *ldap.Conn, baseDn, filter string, fields *config.LdapFields) ([]rawLdapUser, error) { +func LdapFindAllUsers(conn *ldap.Conn, baseDn, filter string, fields *config.LdapFields) ([]RawLdapUser, error) { // Search all users - attrs := ldapSearchAttributes(fields) + attrs := LdapSearchAttributes(fields) searchRequest := ldap.NewSearchRequest( baseDn, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, @@ -27,12 +25,12 @@ func ldapFindAllUsers(conn *ldap.Conn, baseDn, filter string, fields *config.Lda return nil, fmt.Errorf("failed to search: %w", err) } - results := ldapConvertEntries(sr, fields) + results := LdapConvertEntries(sr, fields) return results, nil } -func ldapConnect(cfg *config.LdapProvider) (*ldap.Conn, error) { +func LdapConnect(cfg *config.LdapProvider) (*ldap.Conn, error) { tlsConfig := &tls.Config{InsecureSkipVerify: !cfg.CertValidation} if cfg.TlsCertificatePath != "" { certificate, err := os.ReadFile(cfg.TlsCertificatePath) @@ -72,17 +70,17 @@ func ldapConnect(cfg *config.LdapProvider) (*ldap.Conn, error) { return conn, nil } -func ldapDisconnect(conn *ldap.Conn) { +func LdapDisconnect(conn *ldap.Conn) { if conn != nil { conn.Close() } } -func ldapConvertEntries(sr *ldap.SearchResult, fields *config.LdapFields) []rawLdapUser { - users := make([]rawLdapUser, len(sr.Entries)) +func LdapConvertEntries(sr *ldap.SearchResult, fields *config.LdapFields) []RawLdapUser { + users := make([]RawLdapUser, len(sr.Entries)) for i, entry := range sr.Entries { - userData := make(rawLdapUser) + userData := make(RawLdapUser) userData[fields.UserIdentifier] = entry.DN userData[fields.Email] = entry.GetAttributeValue(fields.Email) userData[fields.Firstname] = entry.GetAttributeValue(fields.Firstname) @@ -96,7 +94,7 @@ func ldapConvertEntries(sr *ldap.SearchResult, fields *config.LdapFields) []rawL return users } -func ldapSearchAttributes(fields *config.LdapFields) []string { +func LdapSearchAttributes(fields *config.LdapFields) []string { attrs := []string{"dn", fields.UserIdentifier} if fields.Email != "" { @@ -118,11 +116,11 @@ func ldapSearchAttributes(fields *config.LdapFields) []string { attrs = append(attrs, fields.GroupMembership) } - return internal.UniqueStringSlice(attrs) + return UniqueStringSlice(attrs) } -// ldapIsMemberOf checks if the groupData array contains the group DN -func ldapIsMemberOf(groupData [][]byte, groupDN *ldap.DN) (bool, error) { +// LdapIsMemberOf checks if the groupData array contains the group DN +func LdapIsMemberOf(groupData [][]byte, groupDN *ldap.DN) (bool, error) { for _, group := range groupData { dn, err := ldap.ParseDN(string(group)) if err != nil { diff --git a/internal/ports/api/core/frontend-dist/assets/UserView-f9bf06a4.js b/internal/ports/api/core/frontend-dist/assets/UserView-f9bf06a4.js deleted file mode 100644 index 784135b..0000000 --- a/internal/ports/api/core/frontend-dist/assets/UserView-f9bf06a4.js +++ /dev/null @@ -1 +0,0 @@ -import{d as T,a as P,A as w,u as A,c as U,r as E,w as O,o as u,b as B,e as x,f as n,_ as M,g as e,h,t as o,i as m,v as g,j as $,k as V,l as k,m as z,F as I,n as D,p as W,q as L,s as F,x as H}from"./index-62a1c0a6.js";const C="/user",N=T({id:"users",state:()=>({userPeers:[],users:[],filter:"",pageSize:10,pageOffset:0,pages:[],fetching:!1}),getters:{Find:t=>l=>t.users.find(i=>i.Identifier===l),Count:t=>t.users.length,FilteredCount:t=>t.Filtered.length,All:t=>t.users,Peers:t=>t.userPeers,Filtered:t=>t.filter?t.users.filter(l=>l.Firstname.includes(t.filter)||l.Lastname.includes(t.filter)||l.Email.includes(t.filter)||l.Identifier.includes(t.filter)):t.users,FilteredAndPaged:t=>t.Filtered.slice(t.pageOffset,t.pageOffset+t.pageSize),isFetching:t=>t.fetching,hasNextPage:t=>t.pageOffsett.pageOffset>0,currentPage:t=>t.pageOffset/t.pageSize+1},actions:{afterPageSizeChange(){this.pageOffset=0,this.calculatePages()},calculatePages(){let t=1;this.pages=[];for(let l=0;l{this.setUsers([]),console.log("Failed to load users: ",t),w({title:"Backend Connection Failure",text:"Failed to load users!"})})},async DeleteUser(t){return this.fetching=!0,P.delete(`${C}/`+t).then(()=>{this.users=this.users.filter(l=>l.Identifier!==t),this.fetching=!1}).catch(l=>{throw this.fetching=!1,console.log(l),new Error(l)})},async UpdateUser(t,l){return this.fetching=!0,P.put(`${C}/`+t,l).then(i=>{let v=this.users.findIndex(_=>_.Identifier===t);this.users[v]=i,this.fetching=!1}).catch(i=>{throw this.fetching=!1,console.log(i),new Error(i)})},async CreateUser(t){return this.fetching=!0,P.post(`${C}/new`,t).then(l=>{this.users.push(l),this.fetching=!1}).catch(l=>{throw this.fetching=!1,console.log(l),new Error(l)})},async LoadUserPeers(t){return this.fetching=!0,P.get(`${C}/${t}/peers`).then(this.setUserPeers).catch(l=>{this.setUserPeers([]),console.log("Failed to load user peers for ",t,": ",l),w({title:"Backend Connection Failure",text:"Failed to load user peers!"})})}}}),j=e("legend",{class:"mt-4"},"General",-1),q={key:0,class:"form-group"},G={class:"form-label mt-4"},K={class:"form-group"},Y={class:"form-label mt-4"},J={key:1,class:"form-group"},Q={class:"form-label mt-4"},R={key:0,id:"passwordHelp",class:"form-text text-muted"},X=e("legend",{class:"mt-4"},"User Information",-1),Z={class:"form-group"},ee={class:"form-label mt-4"},se={class:"row"},te={class:"form-group col-md-6"},le={class:"form-label mt-4"},oe={class:"form-group col-md-6"},ae={class:"form-label mt-4"},ne={class:"row"},ie={class:"form-group col-md-6"},re={class:"form-label mt-4"},de={class:"form-group col-md-6"},ce={class:"form-label mt-4"},ue=e("legend",{class:"mt-4"},"Notes",-1),he={class:"form-group"},pe={class:"form-label mt-4"},fe=e("legend",{class:"mt-4"},"State",-1),me={class:"form-check form-switch"},_e=e("label",{class:"form-check-label"},"Disabled",-1),ve={class:"form-check form-switch"},ge=e("label",{class:"form-check-label"},"Is Admin",-1),be={class:"flex-fill text-start"},$e=["onClick"],ke=["onClick"],ye=["onClick"],Pe={__name:"UserEditModal",props:{userId:String,visible:Boolean},emits:["close"],setup(t,{emit:l}){const i=t,{t:v}=A(),_=N(),a=U(()=>_.Find(i.userId)),d=U(()=>i.visible?a.value?v("users.edit")+": "+a.value.Identifier:v("users.new"):""),s=E(b());function b(){return{Identifier:"",Email:"",Source:"db",IsAdmin:!1,Firstname:"",Lastname:"",Phone:"",Department:"",Notes:"",Password:"",Disabled:!1}}O(()=>i.visible,async(f,r)=>{r===!1&&f===!0&&(a.value?(s.value.Identifier=a.value.Identifier,s.value.Email=a.value.Email,s.value.Source=a.value.Source,s.value.IsAdmin=a.value.IsAdmin,s.value.Firstname=a.value.Firstname,s.value.Lastname=a.value.Lastname,s.value.Phone=a.value.Phone,s.value.Department=a.value.Department,s.value.Notes=a.value.Notes,s.value.Password="",s.value.Disabled=a.value.Disabled):s.value=b())});function p(){s.value=b(),l("close")}async function S(){try{i.userId!=="#NEW#"?await _.UpdateUser(a.value.Identifier,s.value):await _.CreateUser(s.value),p()}catch{w({title:"Backend Connection Failure",text:"Failed to save user!",type:"error"})}}async function y(){try{await _.DeleteUser(a.value.Identifier),p()}catch{w({title:"Backend Connection Failure",text:"Failed to delete user!",type:"error"})}}return(f,r)=>(u(),B(M,{title:n(d),visible:t.visible,onClose:p},{default:x(()=>[e("fieldset",null,[j,i.userId==="#NEW#"?(u(),h("div",q,[e("label",G,o(f.$t("modals.useredit.identifier")),1),m(e("input",{"onUpdate:modelValue":r[0]||(r[0]=c=>s.value.Identifier=c),class:"form-control",placeholder:"The user id",type:"text"},null,512),[[g,s.value.Identifier]])])):$("",!0),e("div",K,[e("label",Y,o(f.$t("modals.useredit.source")),1),m(e("input",{"onUpdate:modelValue":r[1]||(r[1]=c=>s.value.Source=c),class:"form-control",disabled:"disabled",placeholder:"The user source",type:"text"},null,512),[[g,s.value.Source]])]),s.value.Source==="db"?(u(),h("div",J,[e("label",Q,o(f.$t("modals.useredit.password")),1),m(e("input",{"onUpdate:modelValue":r[2]||(r[2]=c=>s.value.Password=c),"aria-describedby":"passwordHelp",class:"form-control",placeholder:"Password",type:"text"},null,512),[[g,s.value.Password]]),i.userId!=="#NEW#"?(u(),h("small",R,"Leave this field blank to keep current password.")):$("",!0)])):$("",!0)]),e("fieldset",null,[X,e("div",Z,[e("label",ee,o(f.$t("modals.useredit.email")),1),m(e("input",{"onUpdate:modelValue":r[3]||(r[3]=c=>s.value.Email=c),class:"form-control",placeholder:"Email",type:"email"},null,512),[[g,s.value.Email]])]),e("div",se,[e("div",te,[e("label",le,o(f.$t("modals.useredit.firstname")),1),m(e("input",{"onUpdate:modelValue":r[4]||(r[4]=c=>s.value.Firstname=c),class:"form-control",placeholder:"Firstname",type:"text"},null,512),[[g,s.value.Firstname]])]),e("div",oe,[e("label",ae,o(f.$t("modals.useredit.lastname")),1),m(e("input",{"onUpdate:modelValue":r[5]||(r[5]=c=>s.value.Lastname=c),class:"form-control",placeholder:"Lastname",type:"text"},null,512),[[g,s.value.Lastname]])])]),e("div",ne,[e("div",ie,[e("label",re,o(f.$t("modals.useredit.phone")),1),m(e("input",{"onUpdate:modelValue":r[6]||(r[6]=c=>s.value.Phone=c),class:"form-control",placeholder:"Phone",type:"text"},null,512),[[g,s.value.Phone]])]),e("div",de,[e("label",ce,o(f.$t("modals.useredit.department")),1),m(e("input",{"onUpdate:modelValue":r[7]||(r[7]=c=>s.value.Department=c),class:"form-control",placeholder:"Department",type:"text"},null,512),[[g,s.value.Department]])])])]),e("fieldset",null,[ue,e("div",he,[e("label",pe,o(f.$t("modals.useredit.notes")),1),m(e("textarea",{"onUpdate:modelValue":r[8]||(r[8]=c=>s.value.Notes=c),class:"form-control",rows:"2"},null,512),[[g,s.value.Notes]])])]),e("fieldset",null,[fe,e("div",me,[m(e("input",{"onUpdate:modelValue":r[9]||(r[9]=c=>s.value.Disabled=c),class:"form-check-input",type:"checkbox"},null,512),[[V,s.value.Disabled]]),_e]),e("div",ve,[m(e("input",{"onUpdate:modelValue":r[10]||(r[10]=c=>s.value.IsAdmin=c),checked:"",class:"form-check-input",type:"checkbox"},null,512),[[V,s.value.IsAdmin]]),ge])])]),footer:x(()=>[e("div",be,[i.userId!=="#NEW#"?(u(),h("button",{key:0,class:"btn btn-danger me-1",type:"button",onClick:k(y,["prevent"])},"Delete",8,$e)):$("",!0)]),e("button",{class:"btn btn-primary me-1",type:"button",onClick:k(S,["prevent"])},"Save",8,ke),e("button",{class:"btn btn-secondary",type:"button",onClick:k(p,["prevent"])},"Discard",8,ye)]),_:1},8,["title","visible"]))}},Ce=e("ul",{class:"nav nav-tabs"},[e("li",{class:"nav-item"},[e("a",{class:"nav-link active","data-bs-toggle":"tab",href:"#user"},"User")]),e("li",{class:"nav-item"},[e("a",{class:"nav-link","data-bs-toggle":"tab",href:"#peers"},"Peers")])],-1),Ue={id:"interfaceTabs",class:"tab-content"},Ie={id:"user",class:"tab-pane fade active show"},we={class:"list-group list-group-flush"},Se={class:"list-group-item"},Fe={class:"table table-sm table-borderless device-status-table"},xe={class:"list-group-item"},De={class:"table table-sm table-borderless device-status-table"},Ee={id:"peers",class:"tab-pane fade"},Ne={key:0,class:"list-group list-group-flush"},Ve={class:"list-group-item"},ze={key:1,id:"peerTable",class:"table table-sm"},Le={scope:"col"},Ae={scope:"col"},Oe=e("th",{scope:"col"},null,-1),Be=["onClick"],Me={__name:"UserViewModal",props:{userId:String,visible:Boolean},emits:["close"],setup(t,{emit:l}){const i=t,{t:v}=A(),_=N(),a=U(()=>{let p=_.Find(i.userId);return p||{}}),d=U(()=>i.visible?v("users.view")+": "+a.value.Identifier:""),s=U(()=>_.Peers);O(()=>i.visible,async(p,S)=>{S===!1&&p===!0&&(console.log(a.value),await _.LoadUserPeers(a.value.Identifier))});function b(){l("close")}return(p,S)=>(u(),B(M,{title:n(d),visible:t.visible,onClose:b},{default:x(()=>[Ce,e("div",Ue,[e("div",Ie,[e("ul",we,[e("li",Se,[z(" User Information: "),e("table",Fe,[e("tbody",null,[e("tr",null,[e("td",null,o(p.$t("users.label.email"))+":",1),e("td",null,o(n(a).Email),1)]),e("tr",null,[e("td",null,o(p.$t("users.label.firstname"))+":",1),e("td",null,o(n(a).Firstname),1)]),e("tr",null,[e("td",null,o(p.$t("users.label.lastname"))+":",1),e("td",null,o(n(a).Lastname),1)]),e("tr",null,[e("td",null,o(p.$t("users.label.phone"))+":",1),e("td",null,o(n(a).Phone),1)]),e("tr",null,[e("td",null,o(p.$t("users.label.department"))+":",1),e("td",null,o(n(a).Department),1)])])])]),e("li",xe,[z(" Notes: "),e("table",De,[e("tbody",null,[e("tr",null,[e("td",null,o(n(a).Notes),1)])])])])])]),e("div",Ee,[n(s).length===0?(u(),h("ul",Ne,[e("li",Ve,o(p.$t("users.nopeers.message")),1)])):$("",!0),n(s).length!==0?(u(),h("table",ze,[e("thead",null,[e("tr",null,[e("th",Le,o(p.$t("user.peers.name")),1),e("th",Ae,o(p.$t("user.peers.ips")),1),Oe])]),e("tbody",null,[(u(!0),h(I,null,D(n(s),y=>(u(),h("tr",{key:y.Identifier},[e("td",null,o(y.DisplayName),1),e("td",null,[(u(!0),h(I,null,D(y.Addresses,f=>(u(),h("span",{key:f,class:"badge rounded-pill bg-light"},o(f),1))),128))])]))),128))])])):$("",!0)])])]),footer:x(()=>[e("button",{class:"btn btn-primary",type:"button",onClick:k(b,["prevent"])},"Close",8,Be)]),_:1},8,["title","visible"]))}},Te={class:"mt-4 row"},We={class:"col-12 col-lg-5"},He={class:"col-12 col-lg-4 text-lg-end"},je={class:"form-group d-inline"},qe={class:"input-group mb-3"},Ge=e("button",{class:"input-group-text btn btn-primary",title:"Search"},[e("i",{class:"fa-solid fa-search"})],-1),Ke={class:"col-12 col-lg-3 text-lg-end"},Ye=e("a",{class:"btn btn-primary",href:"#",title:"Send mail to selected users"},[e("i",{class:"fa fa-paper-plane"})],-1),Je=e("i",{class:"fa fa-plus me-1"},null,-1),Qe=e("i",{class:"fa fa-user"},null,-1),Re=[Je,Qe],Xe={class:"mt-2 table-responsive"},Ze={key:0},es={key:1,id:"userTable",class:"table table-sm"},ss=e("th",{scope:"col"},[e("input",{id:"flexCheckDefault",class:"form-check-input",title:"Select all",type:"checkbox",value:""})],-1),ts={scope:"col"},ls={scope:"col"},os={scope:"col"},as={scope:"col"},ns={class:"text-center",scope:"col"},is={class:"text-center",scope:"col"},rs={class:"text-center",scope:"col"},ds=e("th",{scope:"col"},null,-1),cs=e("th",{scope:"row"},[e("input",{id:"flexCheckDefault",class:"form-check-input",type:"checkbox",value:""})],-1),us={class:"text-center"},hs={class:"badge rounded-pill bg-light"},ps={class:"text-center"},fs={class:"text-center"},ms={key:0,class:"text-danger"},_s=e("i",{class:"fa fa-check-circle"},null,-1),vs=[_s],gs={key:1},bs=e("i",{class:"fa fa-circle-xmark"},null,-1),$s=[bs],ks={class:"text-center"},ys=["onClick"],Ps=e("i",{class:"fa-solid fa-magnifying-glass me-2"},null,-1),Cs=[Ps],Us=["onClick"],Is=e("i",{class:"fas fa-cog me-2"},null,-1),ws=[Is],Ss=e("hr",null,null,-1),Fs={class:"mt-3"},xs={class:"row"},Ds={class:"col-6"},Es={class:"pagination pagination-sm"},Ns=["onClick"],Vs={class:"col-6"},zs={class:"form-group row"},Ls={class:"col-sm-6 col-form-label text-end",for:"paginationSelector"},As={class:"col-sm-6"},Os=e("option",{value:"10"},"10",-1),Bs=e("option",{value:"25"},"25",-1),Ms=e("option",{value:"50"},"50",-1),Ts=e("option",{value:"100"},"100",-1),Ws={value:"999999999"},js={__name:"UserView",setup(t){const l=N(),i=E(""),v=E("");W(()=>{l.LoadUsers()});function _(a){a.Source==="db"?i.value=a.Identifier:w({title:"Forbidden",text:"You can not edit this user!",type:"error"})}return(a,d)=>(u(),h(I,null,[L(Pe,{userId:i.value,visible:i.value!=="",onClose:d[0]||(d[0]=s=>i.value="")},null,8,["userId","visible"]),L(Me,{userId:v.value,visible:v.value!=="",onClose:d[1]||(d[1]=s=>v.value="")},null,8,["userId","visible"]),e("div",Te,[e("div",We,[e("h1",null,o(a.$t("user.h1")),1)]),e("div",He,[e("div",je,[e("div",qe,[m(e("input",{"onUpdate:modelValue":d[2]||(d[2]=s=>n(l).filter=s),class:"form-control",placeholder:"Search...",type:"text",onKeyup:d[3]||(d[3]=(...s)=>n(l).afterPageSizeChange&&n(l).afterPageSizeChange(...s))},null,544),[[g,n(l).filter]]),Ge])])]),e("div",Ke,[Ye,e("a",{class:"btn btn-primary ms-2",href:"#",title:"Add a user",onClick:d[4]||(d[4]=k(s=>i.value="#NEW#",["prevent"]))},Re)])]),e("div",Xe,[n(l).Count===0?(u(),h("div",Ze,[e("h4",null,o(a.$t("users.noUsers.h4")),1),e("p",null,o(a.$t("users.noUsers.message")),1)])):$("",!0),n(l).Count!==0?(u(),h("table",es,[e("thead",null,[e("tr",null,[ss,e("th",ts,o(a.$t("user.id")),1),e("th",ls,o(a.$t("user.email")),1),e("th",os,o(a.$t("user.firstname")),1),e("th",as,o(a.$t("user.lastname")),1),e("th",ns,o(a.$t("user.source")),1),e("th",is,o(a.$t("user.peers")),1),e("th",rs,o(a.$t("user.admin")),1),ds])]),e("tbody",null,[(u(!0),h(I,null,D(n(l).FilteredAndPaged,s=>(u(),h("tr",{key:s.Identifier},[cs,e("td",null,o(s.Identifier),1),e("td",null,o(s.Email),1),e("td",null,o(s.Firstname),1),e("td",null,o(s.Lastname),1),e("td",us,[e("span",hs,o(s.Source),1)]),e("td",ps,o(s.PeerCount),1),e("td",fs,[s.IsAdmin?(u(),h("span",ms,vs)):(u(),h("span",gs,$s))]),e("td",ks,[e("a",{href:"#",title:"Show user",onClick:k(b=>v.value=s.Identifier,["prevent"])},Cs,8,ys),e("a",{class:F({disabled:s.Source!=="db"}),href:"#",title:"Edit user",onClick:k(b=>_(s),["prevent"])},ws,10,Us)])]))),128))])])):$("",!0)]),Ss,e("div",Fs,[e("div",xs,[e("div",Ds,[e("ul",Es,[e("li",{class:F([{disabled:n(l).pageOffset===0},"page-item"])},[e("a",{class:"page-link",onClick:d[5]||(d[5]=(...s)=>n(l).previousPage&&n(l).previousPage(...s))},"«")],2),(u(!0),h(I,null,D(n(l).pages,s=>(u(),h("li",{key:s,class:F([{active:n(l).currentPage===s},"page-item"])},[e("a",{class:"page-link",onClick:b=>n(l).gotoPage(s)},o(s),9,Ns)],2))),128)),e("li",{class:F([{disabled:!n(l).hasNextPage},"page-item"])},[e("a",{class:"page-link",onClick:d[6]||(d[6]=(...s)=>n(l).nextPage&&n(l).nextPage(...s))},"»")],2)])]),e("div",Vs,[e("div",zs,[e("label",Ls,o(a.$t("interfaces.pagination.size"))+":",1),e("div",As,[m(e("select",{"onUpdate:modelValue":d[7]||(d[7]=s=>n(l).pageSize=s),class:"form-select",onClick:d[8]||(d[8]=s=>n(l).afterPageSizeChange())},[Os,Bs,Ms,Ts,e("option",Ws,o(a.$t("interfaces.pagination.all")),1)],512),[[H,n(l).pageSize,void 0,{number:!0}]])])])])])])],64))}};export{js as default};