From 61d8aa658996cf563a1a5c2db1d99bcfc7de7162 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Sun, 8 Jun 2025 11:17:04 +0200 Subject: [PATCH 01/22] fix self-provisioned peer-generation (#452) --- internal/domain/peer.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/domain/peer.go b/internal/domain/peer.go index 4e40a83..8de712a 100644 --- a/internal/domain/peer.go +++ b/internal/domain/peer.go @@ -136,6 +136,7 @@ func (p *Peer) OverwriteUserEditableFields(userPeer *Peer, cfg *config.Config) { p.Interface.PublicKey = userPeer.Interface.PublicKey p.Interface.PrivateKey = userPeer.Interface.PrivateKey p.PresharedKey = userPeer.PresharedKey + p.Identifier = userPeer.Identifier } p.Interface.Mtu = userPeer.Interface.Mtu p.PersistentKeepalive = userPeer.PersistentKeepalive From e3b65ca3370cdad96c414047a0a297fe41fe0119 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Tue, 10 Jun 2025 17:51:45 +0200 Subject: [PATCH 02/22] improve logging of OAuth login issues, decrease auth-code exchange timeout (#451) --- .../app/api/core/assets/doc/v0_swagger.json | 95 ++++++++++--------- .../app/api/core/assets/doc/v0_swagger.yaml | 36 +++---- .../v0/handlers/endpoint_authentication.go | 15 ++- 3 files changed, 80 insertions(+), 66 deletions(-) diff --git a/internal/app/api/core/assets/doc/v0_swagger.json b/internal/app/api/core/assets/doc/v0_swagger.json index 0658046..e7bd238 100644 --- a/internal/app/api/core/assets/doc/v0_swagger.json +++ b/internal/app/api/core/assets/doc/v0_swagger.json @@ -57,6 +57,52 @@ } } }, + "/auth/login/{provider}/callback": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Authentication" + ], + "summary": "Handle the OAuth callback.", + "operationId": "auth_handleOauthCallbackGet", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/model.LoginProviderInfo" + } + } + } + } + } + }, + "/auth/login/{provider}/init": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Authentication" + ], + "summary": "Initiate the OAuth login flow.", + "operationId": "auth_handleOauthInitiateGet", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/model.LoginProviderInfo" + } + } + } + } + } + }, "/auth/logout": { "post": { "produces": [ @@ -275,52 +321,6 @@ } } }, - "/auth/{provider}/callback": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "Authentication" - ], - "summary": "Handle the OAuth callback.", - "operationId": "auth_handleOauthCallbackGet", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/model.LoginProviderInfo" - } - } - } - } - } - }, - "/auth/{provider}/init": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "Authentication" - ], - "summary": "Initiate the OAuth login flow.", - "operationId": "auth_handleOauthInitiateGet", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/model.LoginProviderInfo" - } - } - } - } - } - }, "/config/frontend.js": { "get": { "produces": [ @@ -2234,6 +2234,9 @@ "MailLinkOnly": { "type": "boolean" }, + "MinPasswordLength": { + "type": "integer" + }, "PersistentConfigSupported": { "type": "boolean" }, diff --git a/internal/app/api/core/assets/doc/v0_swagger.yaml b/internal/app/api/core/assets/doc/v0_swagger.yaml index e8778b2..a76b5ca 100644 --- a/internal/app/api/core/assets/doc/v0_swagger.yaml +++ b/internal/app/api/core/assets/doc/v0_swagger.yaml @@ -383,6 +383,8 @@ definitions: type: boolean MailLinkOnly: type: boolean + MinPasswordLength: + type: integer PersistentConfigSupported: type: boolean SelfProvisioning: @@ -472,7 +474,22 @@ paths: summary: Get all available audit entries. Ordered by timestamp. tags: - Audit - /auth/{provider}/callback: + /auth/login: + post: + operationId: auth_handleLoginPost + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/model.LoginProviderInfo' + type: array + summary: Get all available external login providers. + tags: + - Authentication + /auth/login/{provider}/callback: get: operationId: auth_handleOauthCallbackGet produces: @@ -487,7 +504,7 @@ paths: summary: Handle the OAuth callback. tags: - Authentication - /auth/{provider}/init: + /auth/login/{provider}/init: get: operationId: auth_handleOauthInitiateGet produces: @@ -502,21 +519,6 @@ paths: summary: Initiate the OAuth login flow. tags: - Authentication - /auth/login: - post: - operationId: auth_handleLoginPost - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/model.LoginProviderInfo' - type: array - summary: Get all available external login providers. - tags: - - Authentication /auth/logout: post: operationId: auth_handleLogoutPost diff --git a/internal/app/api/v0/handlers/endpoint_authentication.go b/internal/app/api/v0/handlers/endpoint_authentication.go index de412e3..26532b0 100644 --- a/internal/app/api/v0/handlers/endpoint_authentication.go +++ b/internal/app/api/v0/handlers/endpoint_authentication.go @@ -2,6 +2,7 @@ package handlers import ( "context" + "log/slog" "net/http" "net/url" "strconv" @@ -189,7 +190,7 @@ func (e AuthEndpoint) handleSessionInfoGet() http.HandlerFunc { // @Summary Initiate the OAuth login flow. // @Produce json // @Success 200 {object} []model.LoginProviderInfo -// @Router /auth/{provider}/init [get] +// @Router /auth/login/{provider}/init [get] func (e AuthEndpoint) handleOauthInitiateGet() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { currentSession := e.session.GetData(r.Context()) @@ -234,6 +235,8 @@ func (e AuthEndpoint) handleOauthInitiateGet() http.HandlerFunc { authCodeUrl, state, nonce, err := e.authService.OauthLoginStep1(context.Background(), provider) if err != nil { + slog.Debug("failed to create oauth auth code URL", + "provider", provider, "error", err) if autoRedirect && e.isValidReturnUrl(returnTo) { redirectToReturn() } else { @@ -268,7 +271,7 @@ func (e AuthEndpoint) handleOauthInitiateGet() http.HandlerFunc { // @Summary Handle the OAuth callback. // @Produce json // @Success 200 {object} []model.LoginProviderInfo -// @Router /auth/{provider}/callback [get] +// @Router /auth/login/{provider}/callback [get] func (e AuthEndpoint) handleOauthCallbackGet() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { currentSession := e.session.GetData(r.Context()) @@ -306,6 +309,8 @@ func (e AuthEndpoint) handleOauthCallbackGet() http.HandlerFunc { oauthState := request.Query(r, "state") if provider != currentSession.OauthProvider { + slog.Debug("invalid oauth provider in callback", + "expected", currentSession.OauthProvider, "got", provider, "state", oauthState) if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { redirectToReturn() } else { @@ -315,6 +320,8 @@ func (e AuthEndpoint) handleOauthCallbackGet() http.HandlerFunc { return } if oauthState != currentSession.OauthState { + slog.Debug("invalid oauth state in callback", + "expected", currentSession.OauthState, "got", oauthState, "provider", provider) if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { redirectToReturn() } else { @@ -324,11 +331,13 @@ func (e AuthEndpoint) handleOauthCallbackGet() http.HandlerFunc { return } - loginCtx, cancel := context.WithTimeout(context.Background(), 1000*time.Second) + loginCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) // avoid long waits user, err := e.authService.OauthLoginStep2(loginCtx, provider, currentSession.OauthNonce, oauthCode) cancel() if err != nil { + slog.Debug("failed to process oauth code", + "provider", provider, "state", oauthState, "error", err) if returnUrl != nil && e.isValidReturnUrl(returnUrl.String()) { redirectToReturn() } else { From 0c8d6223ce2b7646f02185548a8009cfd7399406 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 20:09:49 +0200 Subject: [PATCH 03/22] chore(deps): bump github.com/go-webauthn/webauthn from 0.12.3 to 0.13.0 (#440) Bumps [github.com/go-webauthn/webauthn](https://github.com/go-webauthn/webauthn) from 0.12.3 to 0.13.0. - [Release notes](https://github.com/go-webauthn/webauthn/releases) - [Commits](https://github.com/go-webauthn/webauthn/compare/v0.12.3...v0.13.0) --- updated-dependencies: - dependency-name: github.com/go-webauthn/webauthn dependency-version: 0.13.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index b83e54c..080fb33 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/go-ldap/ldap/v3 v3.4.11 github.com/go-pkgz/routegroup v1.4.1 github.com/go-playground/validator/v10 v10.26.0 - github.com/go-webauthn/webauthn v0.12.3 + github.com/go-webauthn/webauthn v0.13.0 github.com/google/uuid v1.6.0 github.com/prometheus-community/pro-bing v0.7.0 github.com/prometheus/client_golang v1.22.0 @@ -53,12 +53,12 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-sql-driver/mysql v1.9.2 // indirect github.com/go-test/deep v1.1.1 // indirect - github.com/go-webauthn/x v0.1.20 // indirect + github.com/go-webauthn/x v0.1.21 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/go-tpm v0.9.3 // indirect + github.com/google/go-tpm v0.9.5 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgx/v5 v5.7.4 // indirect diff --git a/go.sum b/go.sum index c427c3f..b47c192 100644 --- a/go.sum +++ b/go.sum @@ -81,10 +81,10 @@ github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRj github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-webauthn/webauthn v0.12.3 h1:hHQl1xkUuabUU9uS+ISNCMLs9z50p9mDUZI/FmkayNE= -github.com/go-webauthn/webauthn v0.12.3/go.mod h1:4JRe8Z3W7HIw8NGEWn2fnUwecoDzkkeach/NnvhkqGY= -github.com/go-webauthn/x v0.1.20 h1:brEBDqfiPtNNCdS/peu8gARtq8fIPsHz0VzpPjGvgiw= -github.com/go-webauthn/x v0.1.20/go.mod h1:n/gAc8ssZJGATM0qThE+W+vfgXiMedsWi3wf/C4lld0= +github.com/go-webauthn/webauthn v0.13.0 h1:cJIL1/1l+22UekVhipziAaSgESJxokYkowUqAIsWs0Y= +github.com/go-webauthn/webauthn v0.13.0/go.mod h1:Oy9o2o79dbLKRPZWWgRIOdtBGAhKnDIaBp2PFkICRHs= +github.com/go-webauthn/x v0.1.21 h1:nFbckQxudvHEJn2uy1VEi713MeSpApoAv9eRqsb9AdQ= +github.com/go-webauthn/x v0.1.21/go.mod h1:sEYohtg1zL4An1TXIUIQ5csdmoO+WO0R4R2pGKaHYKA= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= @@ -96,8 +96,8 @@ github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EO github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-tpm v0.9.3 h1:+yx0/anQuGzi+ssRqeD6WpXjW2L/V0dItUayO0i9sRc= -github.com/google/go-tpm v0.9.3/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU= +github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= From b6bfa1f6dee7a7543aa6e107fe955c49f27b39f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 20:10:32 +0200 Subject: [PATCH 04/22] chore(deps): bump golang.org/x/crypto in the golang group (#454) Bumps the golang group with 1 update: [golang.org/x/crypto](https://github.com/golang/crypto). Updates `golang.org/x/crypto` from 0.38.0 to 0.39.0 - [Commits](https://github.com/golang/crypto/compare/v0.38.0...v0.39.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.39.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index 080fb33..cd2ee79 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/xhit/go-simple-mail/v2 v2.16.0 github.com/yeqown/go-qrcode/v2 v2.2.5 github.com/yeqown/go-qrcode/writer/compressed v1.0.1 - golang.org/x/crypto v0.38.0 + golang.org/x/crypto v0.39.0 golang.org/x/oauth2 v0.30.0 golang.org/x/sys v0.33.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 @@ -87,10 +87,10 @@ require ( github.com/x448/float16 v0.8.4 // indirect github.com/yeqown/reedsolomon v1.0.0 // indirect golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect - golang.org/x/net v0.39.0 // indirect - golang.org/x/sync v0.14.0 // indirect - golang.org/x/text v0.25.0 // indirect - golang.org/x/tools v0.32.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sync v0.15.0 // indirect + golang.org/x/text v0.26.0 // indirect + golang.org/x/tools v0.33.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect google.golang.org/protobuf v1.36.6 // indirect modernc.org/libc v1.63.0 // indirect diff --git a/go.sum b/go.sum index b47c192..5d1b219 100644 --- a/go.sum +++ b/go.sum @@ -232,14 +232,14 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -253,15 +253,15 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -300,14 +300,14 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= 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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= -golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= From cbf8c5bca962858950aa609764fbc8c2bd97b1e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 20:17:12 +0200 Subject: [PATCH 05/22] chore(deps): bump the gorm group across 1 directory with 4 updates (#453) Bumps the gorm group with 3 updates in the / directory: [gorm.io/driver/mysql](https://github.com/go-gorm/mysql), [gorm.io/driver/postgres](https://github.com/go-gorm/postgres) and [gorm.io/driver/sqlserver](https://github.com/go-gorm/sqlserver). Updates `gorm.io/driver/mysql` from 1.5.7 to 1.6.0 - [Commits](https://github.com/go-gorm/mysql/compare/v1.5.7...v1.6.0) Updates `gorm.io/driver/postgres` from 1.5.11 to 1.6.0 - [Commits](https://github.com/go-gorm/postgres/compare/v1.5.11...v1.6.0) Updates `gorm.io/driver/sqlserver` from 1.5.4 to 1.6.0 - [Commits](https://github.com/go-gorm/sqlserver/compare/v1.5.4...v1.6.0) Updates `gorm.io/gorm` from 1.26.1 to 1.30.0 - [Release notes](https://github.com/go-gorm/gorm/releases) - [Commits](https://github.com/go-gorm/gorm/compare/v1.26.1...v1.30.0) --- updated-dependencies: - dependency-name: gorm.io/driver/mysql dependency-version: 1.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gorm - dependency-name: gorm.io/driver/postgres dependency-version: 1.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gorm - dependency-name: gorm.io/driver/sqlserver dependency-version: 1.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gorm - dependency-name: gorm.io/gorm dependency-version: 1.30.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gorm ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++-- go.sum | 125 ++++++++++++++++++++++++++++++--------------------------- 2 files changed, 70 insertions(+), 63 deletions(-) diff --git a/go.mod b/go.mod index cd2ee79..1f2e60c 100644 --- a/go.mod +++ b/go.mod @@ -26,10 +26,10 @@ require ( golang.org/x/sys v0.33.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/mysql v1.5.7 - gorm.io/driver/postgres v1.5.11 - gorm.io/driver/sqlserver v1.5.4 - gorm.io/gorm v1.26.1 + gorm.io/driver/mysql v1.6.0 + gorm.io/driver/postgres v1.6.0 + gorm.io/driver/sqlserver v1.6.0 + gorm.io/gorm v1.30.0 ) require ( diff --git a/go.sum b/go.sum index 5d1b219..4b64484 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,13 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.2/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 h1:jBQA3cKT4L2rWMpgE7Yt3Hwh2aUj8KXjIGLxjHeYNNo= github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= @@ -19,8 +16,7 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= @@ -76,7 +72,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= @@ -85,23 +80,26 @@ github.com/go-webauthn/webauthn v0.13.0 h1:cJIL1/1l+22UekVhipziAaSgESJxokYkowUqA github.com/go-webauthn/webauthn v0.13.0/go.mod h1:Oy9o2o79dbLKRPZWWgRIOdtBGAhKnDIaBp2PFkICRHs= github.com/go-webauthn/x v0.1.21 h1:nFbckQxudvHEJn2uy1VEi713MeSpApoAv9eRqsb9AdQ= github.com/go-webauthn/x v0.1.21/go.mod h1:sEYohtg1zL4An1TXIUIQ5csdmoO+WO0R4R2pGKaHYKA= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU= github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= @@ -121,10 +119,12 @@ github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFK github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= @@ -157,7 +157,7 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/ github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= +github.com/microsoft/go-mssqldb v0.19.0/go.mod h1:ukJCBnnzLzpVF0qYRT+eg1e+eSwjeQ7IvenUv8QPook= github.com/microsoft/go-mssqldb v1.8.0 h1:7cyZ/AT7ycDsEoWPIXibd+aVKFtteUNhDGf3aobP+tw= github.com/microsoft/go-mssqldb v1.8.0/go.mod h1:6znkekS3T2vp0waiMhen4GPU1BiAsrP+iXHcE7a7rFo= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= @@ -165,11 +165,12 @@ github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCL github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= @@ -190,15 +191,10 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= @@ -224,35 +220,38 @@ github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= @@ -260,52 +259,60 @@ golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKl golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= 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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -318,23 +325,23 @@ google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= -gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= -gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= -gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= -gorm.io/driver/sqlserver v1.5.4 h1:xA+Y1KDNspv79q43bPyjDMUgHoYHLhXYmdFcYPobg8g= -gorm.io/driver/sqlserver v1.5.4/go.mod h1:+frZ/qYmuna11zHPlh5oc2O6ZA/lS88Keb0XSH1Zh/g= -gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -gorm.io/gorm v1.26.1 h1:ghB2gUI9FkS46luZtn6DLZ0f6ooBJ5IbVej2ENFDjRw= -gorm.io/gorm v1.26.1/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= +gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= +gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= +gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= +gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= +gorm.io/driver/sqlserver v1.6.0 h1:VZOBQVsVhkHU/NzNhRJKoANt5pZGQAS1Bwc6m6dgfnc= +gorm.io/driver/sqlserver v1.6.0/go.mod h1:WQzt4IJo/WHKnckU9jXBLMJIVNMVeTu25dnOzehntWw= +gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs= +gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= modernc.org/cc/v4 v4.26.0 h1:QMYvbVduUGH0rrO+5mqF/PSPPRZNpRtg2CLELy7vUpA= modernc.org/cc/v4 v4.26.0/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= modernc.org/ccgo/v4 v4.26.0 h1:gVzXaDzGeBYJ2uXTOpR8FR7OlksDOe9jxnjhIKCsiTc= From f0be66aea48e6eff73ea6dbe476034d470a98543 Mon Sep 17 00:00:00 2001 From: "S.J. Louw" <29563018+sj-louw@users.noreply.github.com> Date: Thu, 26 Jun 2025 20:17:45 +0200 Subject: [PATCH 06/22] Option to limit peer count that a normal user can create (#457) --- docs/documentation/configuration/overview.md | 5 ++++ internal/app/wireguard/wireguard_peers.go | 24 +++++++++++++++++ internal/config/config.go | 27 +++++++++++--------- 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/docs/documentation/configuration/overview.md b/docs/documentation/configuration/overview.md index 70496aa..8853af2 100644 --- a/docs/documentation/configuration/overview.md +++ b/docs/documentation/configuration/overview.md @@ -38,6 +38,7 @@ advanced: rule_prio_offset: 20000 route_table_offset: 20000 api_admin_only: true + limit_additional_user_peers: 0 database: debug: false @@ -215,6 +216,10 @@ Additional or more specialized configuration options for logging and interface c - **Default:** `true` - **Description:** If `true`, the public REST API is accessible only to admin users. The API docs live at [`/api/v1/doc.html`](../rest-api/api-doc.md). +### `limit_additional_user_peers` +- **Default:** `0` +- **Description:** Limit additional peers a normal user can create. `0` means unlimited. + --- ## Database diff --git a/internal/app/wireguard/wireguard_peers.go b/internal/app/wireguard/wireguard_peers.go index 2131323..1406e85 100644 --- a/internal/app/wireguard/wireguard_peers.go +++ b/internal/app/wireguard/wireguard_peers.go @@ -188,6 +188,30 @@ func (m Manager) CreatePeer(ctx context.Context, peer *domain.Peer) (*domain.Pee sessionUser := domain.GetUserInfo(ctx) + // Enforce peer limit for non-admin users if LimitAdditionalUserPeers is set + if m.cfg.Core.SelfProvisioningAllowed && !sessionUser.IsAdmin && m.cfg.Advanced.LimitAdditionalUserPeers > 0 { + peers, err := m.db.GetUserPeers(ctx, peer.UserIdentifier) + if err != nil { + return nil, fmt.Errorf("failed to fetch peers for user %s: %w", peer.UserIdentifier, err) + } + // Count enabled peers (disabled IS NULL) + peerCount := 0 + for _, p := range peers { + if !p.IsDisabled() { + peerCount++ + } + } + totalAllowedPeers := 1 + m.cfg.Advanced.LimitAdditionalUserPeers // 1 default peer + x additional peers + if peerCount >= totalAllowedPeers { + slog.WarnContext(ctx, "peer creation blocked due to limit", + "user", peer.UserIdentifier, + "current_count", peerCount, + "allowed_count", totalAllowedPeers) + return nil, fmt.Errorf("peer limit reached (%d peers allowed): %w", totalAllowedPeers, domain.ErrNoPermission) + } + } + + existingPeer, err := m.db.GetPeer(ctx, peer.Identifier) if err != nil && !errors.Is(err, domain.ErrNotFound) { return nil, fmt.Errorf("unable to load existing peer %s: %w", peer.Identifier, err) diff --git a/internal/config/config.go b/internal/config/config.go index f8ade2f..66ff746 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -29,18 +29,19 @@ type Config struct { } `yaml:"core"` Advanced struct { - LogLevel string `yaml:"log_level"` - LogPretty bool `yaml:"log_pretty"` - LogJson bool `yaml:"log_json"` - StartListenPort int `yaml:"start_listen_port"` - StartCidrV4 string `yaml:"start_cidr_v4"` - StartCidrV6 string `yaml:"start_cidr_v6"` - UseIpV6 bool `yaml:"use_ip_v6"` - ConfigStoragePath string `yaml:"config_storage_path"` // keep empty to disable config export to file - ExpiryCheckInterval time.Duration `yaml:"expiry_check_interval"` - RulePrioOffset int `yaml:"rule_prio_offset"` - RouteTableOffset int `yaml:"route_table_offset"` - ApiAdminOnly bool `yaml:"api_admin_only"` // if true, only admin users can access the API + LogLevel string `yaml:"log_level"` + LogPretty bool `yaml:"log_pretty"` + LogJson bool `yaml:"log_json"` + StartListenPort int `yaml:"start_listen_port"` + StartCidrV4 string `yaml:"start_cidr_v4"` + StartCidrV6 string `yaml:"start_cidr_v6"` + UseIpV6 bool `yaml:"use_ip_v6"` + ConfigStoragePath string `yaml:"config_storage_path"` // keep empty to disable config export to file + ExpiryCheckInterval time.Duration `yaml:"expiry_check_interval"` + RulePrioOffset int `yaml:"rule_prio_offset"` + RouteTableOffset int `yaml:"route_table_offset"` + ApiAdminOnly bool `yaml:"api_admin_only"` // if true, only admin users can access the API + LimitAdditionalUserPeers int `yaml:"limit_additional_user_peers"` } `yaml:"advanced"` Statistics struct { @@ -76,6 +77,7 @@ func (c *Config) LogStartupValues() { "reEnablePeerAfterUserEnable", c.Core.ReEnablePeerAfterUserEnable, "deletePeerAfterUserDeleted", c.Core.DeletePeerAfterUserDeleted, "selfProvisioningAllowed", c.Core.SelfProvisioningAllowed, + "limitAdditionalUserPeers", c.Advanced.LimitAdditionalUserPeers, "importExisting", c.Core.ImportExisting, "restoreState", c.Core.RestoreState, "useIpV6", c.Advanced.UseIpV6, @@ -137,6 +139,7 @@ func defaultConfig() *Config { cfg.Advanced.RulePrioOffset = 20000 cfg.Advanced.RouteTableOffset = 20000 cfg.Advanced.ApiAdminOnly = true + cfg.Advanced.LimitAdditionalUserPeers = 0 cfg.Statistics.UsePingChecks = true cfg.Statistics.PingCheckWorkers = 10 From 3a732fd3e5eae78e0882a35a24c145e23d778cea Mon Sep 17 00:00:00 2001 From: HPPinata <83947761+HPPinata@users.noreply.github.com> Date: Thu, 26 Jun 2025 20:20:15 +0200 Subject: [PATCH 07/22] add docker to dependabot (#463) --- .github/dependabot.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1aba90f..007f958 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -28,3 +28,8 @@ updates: patch: update-types: - patch + + - package-ecosystem: "docker" + directory: / + schedule: + interval: weekly From 94785c10ecdc8d49c855ee606e17bd5061463ccd Mon Sep 17 00:00:00 2001 From: h44z Date: Fri, 27 Jun 2025 11:45:44 +0200 Subject: [PATCH 08/22] use website title in mail templates (#448) (#466) * use website title in mail templates (#448) * change button font color to white (#448) --- internal/app/mail/manager.go | 2 +- internal/app/mail/template.go | 6 +++++- internal/app/mail/tpl_files/mail_with_attachment.gohtml | 8 ++++---- internal/app/mail/tpl_files/mail_with_attachment.gotpl | 2 +- internal/app/mail/tpl_files/mail_with_link.gohtml | 8 ++++---- internal/app/mail/tpl_files/mail_with_link.gotpl | 2 +- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/internal/app/mail/manager.go b/internal/app/mail/manager.go index 7b31406..c7ff431 100644 --- a/internal/app/mail/manager.go +++ b/internal/app/mail/manager.go @@ -71,7 +71,7 @@ func NewMailManager( users UserDatabaseRepo, wg WireguardDatabaseRepo, ) (*Manager, error) { - tplHandler, err := newTemplateHandler(cfg.Web.ExternalUrl) + tplHandler, err := newTemplateHandler(cfg.Web.ExternalUrl, cfg.Web.SiteTitle) if err != nil { return nil, fmt.Errorf("failed to initialize template handler: %w", err) } diff --git a/internal/app/mail/template.go b/internal/app/mail/template.go index 15253bf..722d534 100644 --- a/internal/app/mail/template.go +++ b/internal/app/mail/template.go @@ -17,11 +17,12 @@ var TemplateFiles embed.FS // TemplateHandler is a struct that holds the html and text templates. type TemplateHandler struct { portalUrl string + portalName string htmlTemplates *htmlTemplate.Template textTemplates *template.Template } -func newTemplateHandler(portalUrl string) (*TemplateHandler, error) { +func newTemplateHandler(portalUrl, portalName string) (*TemplateHandler, error) { htmlTemplateCache, err := htmlTemplate.New("Html").ParseFS(TemplateFiles, "tpl_files/*.gohtml") if err != nil { return nil, fmt.Errorf("failed to parse html template files: %w", err) @@ -34,6 +35,7 @@ func newTemplateHandler(portalUrl string) (*TemplateHandler, error) { handler := &TemplateHandler{ portalUrl: portalUrl, + portalName: portalName, htmlTemplates: htmlTemplateCache, textTemplates: txtTemplateCache, } @@ -81,6 +83,7 @@ func (c TemplateHandler) GetConfigMailWithAttachment(user *domain.User, cfgName, "ConfigFileName": cfgName, "QrcodePngName": qrName, "PortalUrl": c.portalUrl, + "PortalName": c.portalName, }) if err != nil { return nil, nil, fmt.Errorf("failed to execute template mail_with_attachment.gotpl: %w", err) @@ -91,6 +94,7 @@ func (c TemplateHandler) GetConfigMailWithAttachment(user *domain.User, cfgName, "ConfigFileName": cfgName, "QrcodePngName": qrName, "PortalUrl": c.portalUrl, + "PortalName": c.portalName, }) if err != nil { return nil, nil, fmt.Errorf("failed to execute template mail_with_attachment.gohtml: %w", err) diff --git a/internal/app/mail/tpl_files/mail_with_attachment.gohtml b/internal/app/mail/tpl_files/mail_with_attachment.gohtml index 0243848..0bc5d70 100644 --- a/internal/app/mail/tpl_files/mail_with_attachment.gohtml +++ b/internal/app/mail/tpl_files/mail_with_attachment.gohtml @@ -19,7 +19,7 @@ - Email Template + {{$.PortalName}} - Email Template + {{$.PortalName}} + + + + +
+
+ +
+
+
+ +
+
+ +
diff --git a/internal/app/api/core/assets/doc/v0_swagger.json b/internal/app/api/core/assets/doc/v0_swagger.json index e7bd238..ad07099 100644 --- a/internal/app/api/core/assets/doc/v0_swagger.json +++ b/internal/app/api/core/assets/doc/v0_swagger.json @@ -2231,6 +2231,9 @@ "ApiAdminOnly": { "type": "boolean" }, + "LoginFormVisible": { + "type": "boolean" + }, "MailLinkOnly": { "type": "boolean" }, diff --git a/internal/app/api/core/assets/doc/v0_swagger.yaml b/internal/app/api/core/assets/doc/v0_swagger.yaml index a76b5ca..a788505 100644 --- a/internal/app/api/core/assets/doc/v0_swagger.yaml +++ b/internal/app/api/core/assets/doc/v0_swagger.yaml @@ -381,6 +381,8 @@ definitions: properties: ApiAdminOnly: type: boolean + LoginFormVisible: + type: boolean MailLinkOnly: type: boolean MinPasswordLength: diff --git a/internal/app/api/v0/handlers/endpoint_config.go b/internal/app/api/v0/handlers/endpoint_config.go index a99effe..21b342a 100644 --- a/internal/app/api/v0/handlers/endpoint_config.go +++ b/internal/app/api/v0/handlers/endpoint_config.go @@ -96,10 +96,13 @@ func (e ConfigEndpoint) handleSettingsGet() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { sessionUser := domain.GetUserInfo(r.Context()) + hasSocialLogin := len(e.cfg.Auth.OAuth) > 0 || len(e.cfg.Auth.OpenIDConnect) > 0 || e.cfg.Auth.WebAuthn.Enabled + // For anonymous users, we return the settings object with minimal information if sessionUser.Id == domain.CtxUnknownUserId || sessionUser.Id == "" { respond.JSON(w, http.StatusOK, model.Settings{ - WebAuthnEnabled: e.cfg.Auth.WebAuthn.Enabled, + WebAuthnEnabled: e.cfg.Auth.WebAuthn.Enabled, + LoginFormVisible: !e.cfg.Auth.HideLoginForm || !hasSocialLogin, }) } else { respond.JSON(w, http.StatusOK, model.Settings{ @@ -109,6 +112,7 @@ func (e ConfigEndpoint) handleSettingsGet() http.HandlerFunc { ApiAdminOnly: e.cfg.Advanced.ApiAdminOnly, WebAuthnEnabled: e.cfg.Auth.WebAuthn.Enabled, MinPasswordLength: e.cfg.Auth.MinPasswordLength, + LoginFormVisible: !e.cfg.Auth.HideLoginForm || !hasSocialLogin, }) } } diff --git a/internal/app/api/v0/model/models.go b/internal/app/api/v0/model/models.go index 847b139..5c3ec73 100644 --- a/internal/app/api/v0/model/models.go +++ b/internal/app/api/v0/model/models.go @@ -12,4 +12,5 @@ type Settings struct { ApiAdminOnly bool `json:"ApiAdminOnly"` WebAuthnEnabled bool `json:"WebAuthnEnabled"` MinPasswordLength int `json:"MinPasswordLength"` + LoginFormVisible bool `json:"LoginFormVisible"` } diff --git a/internal/config/auth.go b/internal/config/auth.go index 004fc5b..ef1b994 100644 --- a/internal/config/auth.go +++ b/internal/config/auth.go @@ -21,6 +21,9 @@ type Auth struct { // MinPasswordLength is the minimum password length for user accounts. This also applies to the admin user. // It is encouraged to set this value to at least 16 characters. MinPasswordLength int `yaml:"min_password_length"` + // HideLoginForm specifies whether the login form should be hidden. If no social login providers are configured, + // the login form will be shown regardless of this setting. + HideLoginForm bool `yaml:"hide_login_form"` } // BaseFields contains the basic fields that are used to map user information from the authentication providers. diff --git a/internal/config/config.go b/internal/config/config.go index 66ff746..e64a703 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -95,6 +95,9 @@ func (c *Config) LogStartupValues() { "oidcProviders", len(c.Auth.OpenIDConnect), "oauthProviders", len(c.Auth.OAuth), "ldapProviders", len(c.Auth.Ldap), + "webauthnEnabled", c.Auth.WebAuthn.Enabled, + "minPasswordLength", c.Auth.MinPasswordLength, + "hideLoginForm", c.Auth.HideLoginForm, ) } @@ -169,6 +172,7 @@ func defaultConfig() *Config { cfg.Auth.WebAuthn.Enabled = true cfg.Auth.MinPasswordLength = 16 + cfg.Auth.HideLoginForm = false return cfg } From f08740991b7a33a245b317d7d4153ce1d192a2a2 Mon Sep 17 00:00:00 2001 From: h44z Date: Sun, 29 Jun 2025 19:47:53 +0200 Subject: [PATCH 12/22] support for raw-wireguard and wg-quick style peer configurations (#441) (#473) --- frontend/src/components/PeerViewModal.vue | 39 +++++++++++++++---- frontend/src/lang/translations/de.json | 3 +- frontend/src/lang/translations/en.json | 3 +- frontend/src/stores/peers.js | 8 ++-- .../app/api/core/assets/doc/v0_swagger.json | 18 +++++++++ .../app/api/core/assets/doc/v0_swagger.yaml | 12 ++++++ internal/app/api/v0/backend/peer_service.go | 26 ++++++++----- .../app/api/v0/handlers/endpoint_peers.go | 29 +++++++++++--- .../api/v1/backend/provisioning_service.go | 8 ++-- internal/app/configfile/manager.go | 10 ++--- internal/app/configfile/template.go | 5 ++- internal/app/configfile/tpl_files/wg_peer.tpl | 16 ++++++-- internal/app/mail/manager.go | 20 ++++++---- internal/domain/base.go | 3 ++ 14 files changed, 149 insertions(+), 51 deletions(-) diff --git a/frontend/src/components/PeerViewModal.vue b/frontend/src/components/PeerViewModal.vue index 686ee8d..91c2d86 100644 --- a/frontend/src/components/PeerViewModal.vue +++ b/frontend/src/components/PeerViewModal.vue @@ -50,7 +50,7 @@ const selectedStats = computed(() => { if (!s) { if (!!props.peerId || props.peerId.length) { - p = profile.Statistics(props.peerId) + s = profile.Statistics(props.peerId) } else { s = freshStats() // dummy stats to avoid 'undefined' exceptions } @@ -79,13 +79,19 @@ const title = computed(() => { } }) +const configStyle = ref("wgquick") + watch(() => props.visible, async (newValue, oldValue) => { if (oldValue === false && newValue === true) { // if modal is shown - await peers.LoadPeerConfig(selectedPeer.value.Identifier) + await peers.LoadPeerConfig(selectedPeer.value.Identifier, configStyle.value) configString.value = peers.configuration } -} -) +}) + +watch(() => configStyle.value, async () => { + await peers.LoadPeerConfig(selectedPeer.value.Identifier, configStyle.value) + configString.value = peers.configuration +}) function download() { // credit: https://www.bitdegree.org/learn/javascript-download @@ -103,7 +109,7 @@ function download() { } function email() { - peers.MailPeerConfig(settings.Setting("MailLinkOnly"), [selectedPeer.value.Identifier]).catch(e => { + peers.MailPeerConfig(settings.Setting("MailLinkOnly"), configStyle.value, [selectedPeer.value.Identifier]).catch(e => { notify({ title: "Failed to send mail with peer configuration!", text: e.toString(), @@ -114,7 +120,7 @@ function email() { function ConfigQrUrl() { if (props.peerId.length) { - return apiWrapper.url(`/peer/config-qr/${base64_url_encode(props.peerId)}`) + return apiWrapper.url(`/peer/config-qr/${base64_url_encode(props.peerId)}?style=${configStyle.value}`) } return '' } @@ -124,6 +130,15 @@ function ConfigQrUrl() { - +} + +.btn-switch-group .btn { + border-width: 1px; + padding: 5px; + line-height: 1; +} + diff --git a/frontend/src/lang/translations/de.json b/frontend/src/lang/translations/de.json index ff8af74..859c70e 100644 --- a/frontend/src/lang/translations/de.json +++ b/frontend/src/lang/translations/de.json @@ -467,7 +467,8 @@ "connected-since": "Verbunden seit", "endpoint": "Endpunkt", "button-download": "Konfiguration herunterladen", - "button-email": "Konfiguration per E-Mail senden" + "button-email": "Konfiguration per E-Mail senden", + "style-label": "Konfigurationsformat" }, "peer-edit": { "headline-edit-peer": "Peer bearbeiten:", diff --git a/frontend/src/lang/translations/en.json b/frontend/src/lang/translations/en.json index 06e95e0..57a129a 100644 --- a/frontend/src/lang/translations/en.json +++ b/frontend/src/lang/translations/en.json @@ -468,7 +468,8 @@ "connected-since": "Connected since", "endpoint": "Endpoint", "button-download": "Download configuration", - "button-email": "Send configuration via E-Mail" + "button-email": "Send configuration via E-Mail", + "style-label": "Configuration Style" }, "peer-edit": { "headline-edit-peer": "Edit peer:", diff --git a/frontend/src/stores/peers.js b/frontend/src/stores/peers.js index c59e4c7..c691a01 100644 --- a/frontend/src/stores/peers.js +++ b/frontend/src/stores/peers.js @@ -142,8 +142,8 @@ export const peerStore = defineStore('peers', { }) }) }, - async MailPeerConfig(linkOnly, ids) { - return apiWrapper.post(`${baseUrl}/config-mail`, { + async MailPeerConfig(linkOnly, style, ids) { + return apiWrapper.post(`${baseUrl}/config-mail?style=${style}`, { Identifiers: ids, LinkOnly: linkOnly }) @@ -158,8 +158,8 @@ export const peerStore = defineStore('peers', { throw new Error(error) }) }, - async LoadPeerConfig(id) { - return apiWrapper.get(`${baseUrl}/config/${base64_url_encode(id)}`) + async LoadPeerConfig(id, style) { + return apiWrapper.get(`${baseUrl}/config/${base64_url_encode(id)}?style=${style}`) .then(this.setPeerConfig) .catch(error => { this.configuration = "" diff --git a/internal/app/api/core/assets/doc/v0_swagger.json b/internal/app/api/core/assets/doc/v0_swagger.json index ad07099..fc2ebc8 100644 --- a/internal/app/api/core/assets/doc/v0_swagger.json +++ b/internal/app/api/core/assets/doc/v0_swagger.json @@ -819,6 +819,12 @@ "schema": { "$ref": "#/definitions/model.PeerMailRequest" } + }, + { + "type": "string", + "description": "The configuration style", + "name": "style", + "in": "query" } ], "responses": { @@ -858,6 +864,12 @@ "name": "id", "in": "path", "required": true + }, + { + "type": "string", + "description": "The configuration style", + "name": "style", + "in": "query" } ], "responses": { @@ -899,6 +911,12 @@ "name": "id", "in": "path", "required": true + }, + { + "type": "string", + "description": "The configuration style", + "name": "style", + "in": "query" } ], "responses": { diff --git a/internal/app/api/core/assets/doc/v0_swagger.yaml b/internal/app/api/core/assets/doc/v0_swagger.yaml index a788505..479cb8d 100644 --- a/internal/app/api/core/assets/doc/v0_swagger.yaml +++ b/internal/app/api/core/assets/doc/v0_swagger.yaml @@ -1072,6 +1072,10 @@ paths: required: true schema: $ref: '#/definitions/model.PeerMailRequest' + - description: The configuration style + in: query + name: style + type: string produces: - application/json responses: @@ -1097,6 +1101,10 @@ paths: name: id required: true type: string + - description: The configuration style + in: query + name: style + type: string produces: - image/png - application/json @@ -1125,6 +1133,10 @@ paths: name: id required: true type: string + - description: The configuration style + in: query + name: style + type: string produces: - application/json responses: diff --git a/internal/app/api/v0/backend/peer_service.go b/internal/app/api/v0/backend/peer_service.go index f590693..ab4a7a8 100644 --- a/internal/app/api/v0/backend/peer_service.go +++ b/internal/app/api/v0/backend/peer_service.go @@ -27,12 +27,12 @@ type PeerServicePeerManager interface { } type PeerServiceConfigFileManager interface { - GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) - GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) + GetPeerConfig(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) + GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) } type PeerServiceMailManager interface { - SendPeerEmail(ctx context.Context, linkOnly bool, peers ...domain.PeerIdentifier) error + SendPeerEmail(ctx context.Context, linkOnly bool, style string, peers ...domain.PeerIdentifier) error } // endregion dependencies @@ -95,16 +95,24 @@ func (p PeerService) DeletePeer(ctx context.Context, id domain.PeerIdentifier) e return p.peers.DeletePeer(ctx, id) } -func (p PeerService) GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) { - return p.configFile.GetPeerConfig(ctx, id) +func (p PeerService) GetPeerConfig(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) { + return p.configFile.GetPeerConfig(ctx, id, style) } -func (p PeerService) GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) { - return p.configFile.GetPeerConfigQrCode(ctx, id) +func (p PeerService) GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier, style string) ( + io.Reader, + error, +) { + return p.configFile.GetPeerConfigQrCode(ctx, id, style) } -func (p PeerService) SendPeerEmail(ctx context.Context, linkOnly bool, peers ...domain.PeerIdentifier) error { - return p.mailer.SendPeerEmail(ctx, linkOnly, peers...) +func (p PeerService) SendPeerEmail( + ctx context.Context, + linkOnly bool, + style string, + peers ...domain.PeerIdentifier, +) error { + return p.mailer.SendPeerEmail(ctx, linkOnly, style, peers...) } func (p PeerService) GetPeerStats(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.PeerStatus, error) { diff --git a/internal/app/api/v0/handlers/endpoint_peers.go b/internal/app/api/v0/handlers/endpoint_peers.go index d9a0115..e60a3aa 100644 --- a/internal/app/api/v0/handlers/endpoint_peers.go +++ b/internal/app/api/v0/handlers/endpoint_peers.go @@ -34,11 +34,11 @@ type PeerService interface { // DeletePeer deletes the peer with the given id. DeletePeer(ctx context.Context, id domain.PeerIdentifier) error // GetPeerConfig returns the peer configuration for the given id. - GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) + GetPeerConfig(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) // GetPeerConfigQrCode returns the peer configuration as qr code for the given id. - GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) + GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) // SendPeerEmail sends the peer configuration via email. - SendPeerEmail(ctx context.Context, linkOnly bool, peers ...domain.PeerIdentifier) error + SendPeerEmail(ctx context.Context, linkOnly bool, style string, peers ...domain.PeerIdentifier) error // GetPeerStats returns the peer stats for the given interface. GetPeerStats(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.PeerStatus, error) } @@ -355,6 +355,7 @@ func (e PeerEndpoint) handleDelete() http.HandlerFunc { // @Summary Get peer configuration as string. // @Produce json // @Param id path string true "The peer identifier" +// @Param style query string false "The configuration style" // @Success 200 {object} string // @Failure 400 {object} model.Error // @Failure 500 {object} model.Error @@ -369,7 +370,9 @@ func (e PeerEndpoint) handleConfigGet() http.HandlerFunc { return } - configTxt, err := e.peerService.GetPeerConfig(r.Context(), domain.PeerIdentifier(id)) + configStyle := e.getConfigStyle(r) + + configTxt, err := e.peerService.GetPeerConfig(r.Context(), domain.PeerIdentifier(id), configStyle) if err != nil { respond.JSON(w, http.StatusInternalServerError, model.Error{ Code: http.StatusInternalServerError, Message: err.Error(), @@ -397,6 +400,7 @@ func (e PeerEndpoint) handleConfigGet() http.HandlerFunc { // @Produce png // @Produce json // @Param id path string true "The peer identifier" +// @Param style query string false "The configuration style" // @Success 200 {file} binary // @Failure 400 {object} model.Error // @Failure 500 {object} model.Error @@ -411,7 +415,9 @@ func (e PeerEndpoint) handleQrCodeGet() http.HandlerFunc { return } - configQr, err := e.peerService.GetPeerConfigQrCode(r.Context(), domain.PeerIdentifier(id)) + configStyle := e.getConfigStyle(r) + + configQr, err := e.peerService.GetPeerConfigQrCode(r.Context(), domain.PeerIdentifier(id), configStyle) if err != nil { respond.JSON(w, http.StatusInternalServerError, model.Error{ Code: http.StatusInternalServerError, Message: err.Error(), @@ -438,6 +444,7 @@ func (e PeerEndpoint) handleQrCodeGet() http.HandlerFunc { // @Summary Send peer configuration via email. // @Produce json // @Param request body model.PeerMailRequest true "The peer mail request data" +// @Param style query string false "The configuration style" // @Success 204 "No content if mail sending was successful" // @Failure 400 {object} model.Error // @Failure 500 {object} model.Error @@ -460,11 +467,13 @@ func (e PeerEndpoint) handleEmailPost() http.HandlerFunc { return } + configStyle := e.getConfigStyle(r) + peerIds := make([]domain.PeerIdentifier, len(req.Identifiers)) for i := range req.Identifiers { peerIds[i] = domain.PeerIdentifier(req.Identifiers[i]) } - if err := e.peerService.SendPeerEmail(r.Context(), req.LinkOnly, peerIds...); err != nil { + if err := e.peerService.SendPeerEmail(r.Context(), req.LinkOnly, configStyle, peerIds...); err != nil { respond.JSON(w, http.StatusInternalServerError, model.Error{Code: http.StatusInternalServerError, Message: err.Error()}) return @@ -504,3 +513,11 @@ func (e PeerEndpoint) handleStatsGet() http.HandlerFunc { respond.JSON(w, http.StatusOK, model.NewPeerStats(e.cfg.Statistics.CollectPeerData, stats)) } } + +func (e PeerEndpoint) getConfigStyle(r *http.Request) string { + configStyle := request.QueryDefault(r, "style", domain.ConfigStyleWgQuick) + if configStyle != domain.ConfigStyleWgQuick && configStyle != domain.ConfigStyleRaw { + configStyle = domain.ConfigStyleWgQuick // default to wg-quick style + } + return configStyle +} diff --git a/internal/app/api/v1/backend/provisioning_service.go b/internal/app/api/v1/backend/provisioning_service.go index 4e14ecb..88bbfee 100644 --- a/internal/app/api/v1/backend/provisioning_service.go +++ b/internal/app/api/v1/backend/provisioning_service.go @@ -23,8 +23,8 @@ type ProvisioningServicePeerManagerRepo interface { } type ProvisioningServiceConfigFileManagerRepo interface { - GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) - GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) + GetPeerConfig(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) + GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) } type ProvisioningService struct { @@ -96,7 +96,7 @@ func (p ProvisioningService) GetPeerConfig(ctx context.Context, peerId domain.Pe return nil, err } - peerCfgReader, err := p.configFiles.GetPeerConfig(ctx, peer.Identifier) + peerCfgReader, err := p.configFiles.GetPeerConfig(ctx, peer.Identifier, domain.ConfigStyleWgQuick) if err != nil { return nil, err } @@ -119,7 +119,7 @@ func (p ProvisioningService) GetPeerQrPng(ctx context.Context, peerId domain.Pee return nil, err } - peerCfgQrReader, err := p.configFiles.GetPeerConfigQrCode(ctx, peer.Identifier) + peerCfgQrReader, err := p.configFiles.GetPeerConfigQrCode(ctx, peer.Identifier, domain.ConfigStyleWgQuick) if err != nil { return nil, err } diff --git a/internal/app/configfile/manager.go b/internal/app/configfile/manager.go index 83c07f4..94f06ae 100644 --- a/internal/app/configfile/manager.go +++ b/internal/app/configfile/manager.go @@ -46,7 +46,7 @@ type TemplateRenderer interface { // GetInterfaceConfig returns the configuration file for the given interface. GetInterfaceConfig(iface *domain.Interface, peers []domain.Peer) (io.Reader, error) // GetPeerConfig returns the configuration file for the given peer. - GetPeerConfig(peer *domain.Peer) (io.Reader, error) + GetPeerConfig(peer *domain.Peer, style string) (io.Reader, error) } type EventBus interface { @@ -186,7 +186,7 @@ func (m Manager) GetInterfaceConfig(ctx context.Context, id domain.InterfaceIden // GetPeerConfig returns the configuration file for the given peer. // The file is structured in wg-quick format. -func (m Manager) GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) { +func (m Manager) GetPeerConfig(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) { peer, err := m.wg.GetPeer(ctx, id) if err != nil { return nil, fmt.Errorf("failed to fetch peer %s: %w", id, err) @@ -196,11 +196,11 @@ func (m Manager) GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (i return nil, err } - return m.tplHandler.GetPeerConfig(peer) + return m.tplHandler.GetPeerConfig(peer, style) } // GetPeerConfigQrCode returns a QR code image containing the configuration for the given peer. -func (m Manager) GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) { +func (m Manager) GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) { peer, err := m.wg.GetPeer(ctx, id) if err != nil { return nil, fmt.Errorf("failed to fetch peer %s: %w", id, err) @@ -210,7 +210,7 @@ func (m Manager) GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifi return nil, err } - cfgData, err := m.tplHandler.GetPeerConfig(peer) + cfgData, err := m.tplHandler.GetPeerConfig(peer, style) if err != nil { return nil, fmt.Errorf("failed to get peer config for %s: %w", id, err) } diff --git a/internal/app/configfile/template.go b/internal/app/configfile/template.go index ed40d9b..773ab8c 100644 --- a/internal/app/configfile/template.go +++ b/internal/app/configfile/template.go @@ -55,11 +55,12 @@ func (c TemplateHandler) GetInterfaceConfig(cfg *domain.Interface, peers []domai } // GetPeerConfig returns the rendered configuration file for a WireGuard peer. -func (c TemplateHandler) GetPeerConfig(peer *domain.Peer) (io.Reader, error) { +func (c TemplateHandler) GetPeerConfig(peer *domain.Peer, style string) (io.Reader, error) { var tplBuff bytes.Buffer err := c.templates.ExecuteTemplate(&tplBuff, "wg_peer.tpl", map[string]any{ - "Peer": peer, + "Style": style, + "Peer": peer, "Portal": map[string]any{ "Version": "unknown", }, diff --git a/internal/app/configfile/tpl_files/wg_peer.tpl b/internal/app/configfile/tpl_files/wg_peer.tpl index 8a4bae4..211546b 100644 --- a/internal/app/configfile/tpl_files/wg_peer.tpl +++ b/internal/app/configfile/tpl_files/wg_peer.tpl @@ -1,6 +1,8 @@ # AUTOGENERATED FILE - DO NOT EDIT -# This file uses wg-quick format. +# This file uses {{ .Style }} format. +{{- if eq .Style "wgquick"}} # See https://man7.org/linux/man-pages/man8/wg-quick.8.html#CONFIGURATION +{{- end}} # Lines starting with the -WGP- tag are used by # the WireGuard Portal configuration parser. @@ -21,22 +23,27 @@ # Core settings PrivateKey = {{ .Peer.Interface.KeyPair.PrivateKey }} +{{- if eq .Style "wgquick"}} Address = {{ CidrsToString .Peer.Interface.Addresses }} +{{- end}} # Misc. settings (optional) +{{- if eq .Style "wgquick"}} {{- if .Peer.Interface.DnsStr.GetValue}} DNS = {{ .Peer.Interface.DnsStr.GetValue }} {{- if .Peer.Interface.DnsSearchStr.GetValue}}, {{ .Peer.Interface.DnsSearchStr.GetValue }} {{- end}} {{- end}} {{- if ne .Peer.Interface.Mtu.GetValue 0}} MTU = {{ .Peer.Interface.Mtu.GetValue }} {{- end}} -{{- if ne .Peer.Interface.FirewallMark.GetValue 0}} -FwMark = {{ .Peer.Interface.FirewallMark.GetValue }} -{{- end}} {{- if ne .Peer.Interface.RoutingTable.GetValue ""}} Table = {{ .Peer.Interface.RoutingTable.GetValue }} {{- end}} +{{- end}} +{{- if ne .Peer.Interface.FirewallMark.GetValue 0}} +FwMark = {{ .Peer.Interface.FirewallMark.GetValue }} +{{- end}} +{{- if eq .Style "wgquick"}} # Interface hooks (optional) {{- if .Peer.Interface.PreUp.GetValue}} PreUp = {{ .Peer.Interface.PreUp.GetValue }} @@ -50,6 +57,7 @@ PreDown = {{ .Peer.Interface.PreDown.GetValue }} {{- if .Peer.Interface.PostDown.GetValue}} PostDown = {{ .Peer.Interface.PostDown.GetValue }} {{- end}} +{{- end}} [Peer] PublicKey = {{ .Peer.EndpointPublicKey.GetValue }} diff --git a/internal/app/mail/manager.go b/internal/app/mail/manager.go index c7ff431..7b9b3b9 100644 --- a/internal/app/mail/manager.go +++ b/internal/app/mail/manager.go @@ -21,9 +21,9 @@ type ConfigFileManager interface { // GetInterfaceConfig returns the configuration for the given interface. GetInterfaceConfig(ctx context.Context, id domain.InterfaceIdentifier) (io.Reader, error) // GetPeerConfig returns the configuration for the given peer. - GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) + GetPeerConfig(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) // GetPeerConfigQrCode returns the QR code for the given peer. - GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) + GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifier, style string) (io.Reader, error) } type UserDatabaseRepo interface { @@ -89,7 +89,7 @@ func NewMailManager( } // SendPeerEmail sends an email to the user linked to the given peers. -func (m Manager) SendPeerEmail(ctx context.Context, linkOnly bool, peers ...domain.PeerIdentifier) error { +func (m Manager) SendPeerEmail(ctx context.Context, linkOnly bool, style string, peers ...domain.PeerIdentifier) error { for _, peerId := range peers { peer, err := m.wg.GetPeer(ctx, peerId) if err != nil { @@ -123,7 +123,7 @@ func (m Manager) SendPeerEmail(ctx context.Context, linkOnly bool, peers ...doma continue } - err = m.sendPeerEmail(ctx, linkOnly, user, peer) + err = m.sendPeerEmail(ctx, linkOnly, style, user, peer) if err != nil { return fmt.Errorf("failed to send peer email for %s: %w", peerId, err) } @@ -132,7 +132,13 @@ func (m Manager) SendPeerEmail(ctx context.Context, linkOnly bool, peers ...doma return nil } -func (m Manager) sendPeerEmail(ctx context.Context, linkOnly bool, user *domain.User, peer *domain.Peer) error { +func (m Manager) sendPeerEmail( + ctx context.Context, + linkOnly bool, + style string, + user *domain.User, + peer *domain.Peer, +) error { qrName := "WireGuardQRCode.png" configName := peer.GetConfigFileName() @@ -148,12 +154,12 @@ func (m Manager) sendPeerEmail(ctx context.Context, linkOnly bool, user *domain. } } else { - peerConfig, err := m.configFiles.GetPeerConfig(ctx, peer.Identifier) + peerConfig, err := m.configFiles.GetPeerConfig(ctx, peer.Identifier, style) if err != nil { return fmt.Errorf("failed to fetch peer config for %s: %w", peer.Identifier, err) } - peerConfigQr, err := m.configFiles.GetPeerConfigQrCode(ctx, peer.Identifier) + peerConfigQr, err := m.configFiles.GetPeerConfigQrCode(ctx, peer.Identifier, style) if err != nil { return fmt.Errorf("failed to fetch peer config QR code for %s: %w", peer.Identifier, err) } diff --git a/internal/domain/base.go b/internal/domain/base.go index 5f549e7..f248ffe 100644 --- a/internal/domain/base.go +++ b/internal/domain/base.go @@ -62,4 +62,7 @@ const ( LockedReasonAdmin = "locked by admin" LockedReasonApi = "locked by admin" + + ConfigStyleRaw = "raw" + ConfigStyleWgQuick = "wgquick" ) From 588bbca14134e836c18fe4be3528341f24603a32 Mon Sep 17 00:00:00 2001 From: h44z Date: Sun, 29 Jun 2025 19:48:46 +0200 Subject: [PATCH 13/22] only execute interface hooks if the state has changed (#469) (#472) --- .../app/wireguard/wireguard_interfaces.go | 51 +++++++------------ 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/internal/app/wireguard/wireguard_interfaces.go b/internal/app/wireguard/wireguard_interfaces.go index f232eec..02f1da1 100644 --- a/internal/app/wireguard/wireguard_interfaces.go +++ b/internal/app/wireguard/wireguard_interfaces.go @@ -461,7 +461,7 @@ func (m Manager) DeleteInterface(ctx context.Context, id domain.InterfaceIdentif physicalInterface, _ := m.wg.GetInterface(ctx, id) - if err := m.handleInterfacePreSaveHooks(true, existingInterface); err != nil { + if err := m.handleInterfacePreSaveHooks(existingInterface, !existingInterface.IsDisabled(), false); err != nil { return fmt.Errorf("pre-delete hooks failed: %w", err) } @@ -490,7 +490,7 @@ func (m Manager) DeleteInterface(ctx context.Context, id domain.InterfaceIdentif Table: existingInterface.GetRoutingTable(), }) - if err := m.handleInterfacePostSaveHooks(true, existingInterface); err != nil { + if err := m.handleInterfacePostSaveHooks(existingInterface, !existingInterface.IsDisabled(), false); err != nil { return fmt.Errorf("post-delete hooks failed: %w", err) } @@ -509,9 +509,9 @@ func (m Manager) saveInterface(ctx context.Context, iface *domain.Interface) ( return nil, fmt.Errorf("interface validation failed: %w", err) } - stateChanged := m.hasInterfaceStateChanged(ctx, iface) + oldEnabled, newEnabled := m.getInterfaceStateHistory(ctx, iface) - if err := m.handleInterfacePreSaveHooks(stateChanged, iface); err != nil { + if err := m.handleInterfacePreSaveHooks(iface, oldEnabled, newEnabled); err != nil { return nil, fmt.Errorf("pre-save hooks failed: %w", err) } @@ -551,7 +551,7 @@ func (m Manager) saveInterface(ctx context.Context, iface *domain.Interface) ( m.bus.Publish(app.TopicRouteUpdate, "interface updated: "+string(iface.Identifier)) } - if err := m.handleInterfacePostSaveHooks(stateChanged, iface); err != nil { + if err := m.handleInterfacePostSaveHooks(iface, oldEnabled, newEnabled); err != nil { return nil, fmt.Errorf("post-save hooks failed: %w", err) } @@ -566,32 +566,13 @@ func (m Manager) saveInterface(ctx context.Context, iface *domain.Interface) ( return iface, nil } -func (m Manager) hasInterfaceStateChanged(ctx context.Context, iface *domain.Interface) bool { +func (m Manager) getInterfaceStateHistory(ctx context.Context, iface *domain.Interface) (oldEnabled, newEnabled bool) { oldInterface, err := m.db.GetInterface(ctx, iface.Identifier) if err != nil { - return false + return false, !iface.IsDisabled() // if the interface did not exist, we assume it was not enabled } - if oldInterface.IsDisabled() != iface.IsDisabled() { - return true // interface in db has changed - } - - wgInterface, err := m.wg.GetInterface(ctx, iface.Identifier) - if err != nil { - return true // interface might not exist - so we assume that there must be a change - } - - // compare physical interface settings - if len(wgInterface.Addresses) != len(iface.Addresses) || - wgInterface.Mtu != iface.Mtu || - wgInterface.FirewallMark != iface.FirewallMark || - wgInterface.ListenPort != iface.ListenPort || - wgInterface.PrivateKey != iface.PrivateKey || - wgInterface.PublicKey != iface.PublicKey { - return true - } - - return false + return !oldInterface.IsDisabled(), !iface.IsDisabled() } func (m Manager) handleInterfacePreSaveActions(iface *domain.Interface) error { @@ -607,12 +588,14 @@ func (m Manager) handleInterfacePreSaveActions(iface *domain.Interface) error { return nil } -func (m Manager) handleInterfacePreSaveHooks(stateChanged bool, iface *domain.Interface) error { - if !stateChanged { +func (m Manager) handleInterfacePreSaveHooks(iface *domain.Interface, oldEnabled, newEnabled bool) error { + if oldEnabled == newEnabled { return nil // do nothing if state did not change } - if !iface.IsDisabled() { + slog.Debug("executing pre-save hooks", "interface", iface.Identifier, "up", newEnabled) + + if newEnabled { if err := m.quick.ExecuteInterfaceHook(iface.Identifier, iface.PreUp); err != nil { return fmt.Errorf("failed to execute pre-up hook: %w", err) } @@ -624,12 +607,14 @@ func (m Manager) handleInterfacePreSaveHooks(stateChanged bool, iface *domain.In return nil } -func (m Manager) handleInterfacePostSaveHooks(stateChanged bool, iface *domain.Interface) error { - if !stateChanged { +func (m Manager) handleInterfacePostSaveHooks(iface *domain.Interface, oldEnabled, newEnabled bool) error { + if oldEnabled == newEnabled { return nil // do nothing if state did not change } - if !iface.IsDisabled() { + slog.Debug("executing post-save hooks", "interface", iface.Identifier, "up", newEnabled) + + if newEnabled { if err := m.quick.ExecuteInterfaceHook(iface.Identifier, iface.PostUp); err != nil { return fmt.Errorf("failed to execute post-up hook: %w", err) } From edb88b5768d25a4cce1d352a05ea6d02f606c19f Mon Sep 17 00:00:00 2001 From: h44z Date: Sun, 29 Jun 2025 19:49:01 +0200 Subject: [PATCH 14/22] new webhook models (#444) (#471) warning: existing webhook receivers need to be adapted to the new models --- docs/documentation/configuration/overview.md | 13 - docs/documentation/usage/webhooks.md | 237 +++++++++++++++++-- internal/app/webhooks/manager.go | 43 ++-- internal/app/webhooks/model.go | 7 +- internal/app/webhooks/models/interface.go | 99 ++++++++ internal/app/webhooks/models/peer.go | 89 +++++++ internal/app/webhooks/models/peer_metrics.go | 50 ++++ internal/app/webhooks/models/user.go | 56 +++++ internal/app/wireguard/statistics.go | 10 +- 9 files changed, 546 insertions(+), 58 deletions(-) create mode 100644 internal/app/webhooks/models/interface.go create mode 100644 internal/app/webhooks/models/peer.go create mode 100644 internal/app/webhooks/models/peer_metrics.go create mode 100644 internal/app/webhooks/models/user.go diff --git a/docs/documentation/configuration/overview.md b/docs/documentation/configuration/overview.md index 3611171..dd20d79 100644 --- a/docs/documentation/configuration/overview.md +++ b/docs/documentation/configuration/overview.md @@ -673,19 +673,6 @@ Without a valid `external_url`, the login process may fail due to CSRF protectio ## Webhook The webhook section allows you to configure a webhook that is called on certain events in WireGuard Portal. -A JSON object is sent in a POST request to the webhook URL with the following structure: -```json -{ - "event": "update", - "entity": "peer", - "identifier": "the-peer-identifier", - "payload": { - // The payload of the event, e.g. peer data. - // Check the API documentation for the exact structure. - } -} -``` - Further details can be found in the [usage documentation](../usage/webhooks.md). ### `url` diff --git a/docs/documentation/usage/webhooks.md b/docs/documentation/usage/webhooks.md index 7ec8cbf..1d0c692 100644 --- a/docs/documentation/usage/webhooks.md +++ b/docs/documentation/usage/webhooks.md @@ -38,11 +38,12 @@ WireGuard Portal supports various events that can trigger webhooks. The followin - `connect`: Triggered when a user connects to the VPN. - `disconnect`: Triggered when a user disconnects from the VPN. -The following entity types can trigger webhooks: +The following entity models are supported for webhook events: -- `user`: When a WireGuard Portal user is created, updated, or deleted. -- `peer`: When a peer is created, updated, or deleted. This entity can also trigger `connect` and `disconnect` events. -- `interface`: When a device is created, updated, or deleted. +- `user`: WireGuard Portal users support creation, update, or deletion events. +- `peer`: Peers support creation, update, or deletion events. Via the `peer_metric` entity, you can also receive connection status updates. +- `peer_metric`: Peer metrics support connection status updates, such as when a peer connects or disconnects. +- `interface`: WireGuard interfaces support creation, update, or deletion events. ## Payload Structure @@ -51,36 +52,234 @@ A common shell structure for webhook payloads is as follows: ```json { - "event": "create", - "entity": "user", - "identifier": "the-user-identifier", + "event": "create", // The event type, e.g. "create", "update", "delete", "connect", "disconnect" + "entity": "user", // The entity type, e.g. "user", "peer", "peer_metric", "interface" + "identifier": "the-user-identifier", // Unique identifier of the entity, e.g. user ID or peer ID "payload": { - // The payload of the event, e.g. peer data. - // Check the API documentation for the exact structure. + // The payload of the event, e.g. a Peer model. + // Detailed model descriptions are provided below. } } ``` +### Payload Models -### Example Payload +All payload models are encoded as JSON objects. Fields with empty values might be omitted in the payload. + +#### User Payload (entity: `user`) + +| JSON Field | Type | Description | +|----------------|-------------|-----------------------------------| +| CreatedBy | string | Creator identifier | +| UpdatedBy | string | Last updater identifier | +| CreatedAt | time.Time | Time of creation | +| UpdatedAt | time.Time | Time of last update | +| Identifier | string | Unique user identifier | +| Email | string | User email | +| Source | string | Authentication source | +| ProviderName | string | Name of auth provider | +| IsAdmin | bool | Whether user has admin privileges | +| Firstname | string | User's first name (optional) | +| Lastname | string | User's last name (optional) | +| Phone | string | Contact phone number (optional) | +| Department | string | User's department (optional) | +| Notes | string | Additional notes (optional) | +| Disabled | *time.Time | When user was disabled | +| DisabledReason | string | Reason for deactivation | +| Locked | *time.Time | When user account was locked | +| LockedReason | string | Reason for being locked | + + +#### Peer Payload (entity: `peer`) + +| JSON Field | Type | Description | +|----------------------|------------|----------------------------------------| +| CreatedBy | string | Creator identifier | +| UpdatedBy | string | Last updater identifier | +| CreatedAt | time.Time | Creation timestamp | +| UpdatedAt | time.Time | Last update timestamp | +| Endpoint | string | Peer endpoint address | +| EndpointPublicKey | string | Public key of peer endpoint | +| AllowedIPsStr | string | Allowed IPs | +| ExtraAllowedIPsStr | string | Extra allowed IPs | +| PresharedKey | string | Pre-shared key for encryption | +| PersistentKeepalive | int | Keepalive interval in seconds | +| DisplayName | string | Display name of the peer | +| Identifier | string | Unique identifier | +| UserIdentifier | string | Associated user ID (optional) | +| InterfaceIdentifier | string | Interface this peer is attached to | +| Disabled | *time.Time | When the peer was disabled | +| DisabledReason | string | Reason for being disabled | +| ExpiresAt | *time.Time | Expiration date | +| Notes | string | Notes for this peer | +| AutomaticallyCreated | bool | Whether peer was auto-generated | +| PrivateKey | string | Peer private key | +| PublicKey | string | Peer public key | +| InterfaceType | string | Type of the peer interface | +| Addresses | []string | IP addresses | +| CheckAliveAddress | string | Address used for alive checks | +| DnsStr | string | DNS servers | +| DnsSearchStr | string | DNS search domains | +| Mtu | int | MTU (Maximum Transmission Unit) | +| FirewallMark | uint32 | Firewall mark (optional) | +| RoutingTable | string | Custom routing table (optional) | +| PreUp | string | Command before bringing up interface | +| PostUp | string | Command after bringing up interface | +| PreDown | string | Command before bringing down interface | +| PostDown | string | Command after bringing down interface | + + +#### Interface Payload (entity: `interface`) + +| JSON Field | Type | Description | +|----------------------------|------------|----------------------------------------| +| CreatedBy | string | Creator identifier | +| UpdatedBy | string | Last updater identifier | +| CreatedAt | time.Time | Creation timestamp | +| UpdatedAt | time.Time | Last update timestamp | +| Identifier | string | Unique identifier | +| PrivateKey | string | Private key for the interface | +| PublicKey | string | Public key for the interface | +| ListenPort | int | Listening port | +| Addresses | []string | IP addresses | +| DnsStr | string | DNS servers | +| DnsSearchStr | string | DNS search domains | +| Mtu | int | MTU (Maximum Transmission Unit) | +| FirewallMark | uint32 | Firewall mark | +| RoutingTable | string | Custom routing table | +| PreUp | string | Command before bringing up interface | +| PostUp | string | Command after bringing up interface | +| PreDown | string | Command before bringing down interface | +| PostDown | string | Command after bringing down interface | +| SaveConfig | bool | Whether to save config to file | +| DisplayName | string | Human-readable name | +| Type | string | Type of interface | +| DriverType | string | Driver used | +| Disabled | *time.Time | When the interface was disabled | +| DisabledReason | string | Reason for being disabled | +| PeerDefNetworkStr | string | Default peer network configuration | +| PeerDefDnsStr | string | Default peer DNS servers | +| PeerDefDnsSearchStr | string | Default peer DNS search domains | +| PeerDefEndpoint | string | Default peer endpoint | +| PeerDefAllowedIPsStr | string | Default peer allowed IPs | +| PeerDefMtu | int | Default peer MTU | +| PeerDefPersistentKeepalive | int | Default keepalive value | +| PeerDefFirewallMark | uint32 | Default firewall mark for peers | +| PeerDefRoutingTable | string | Default routing table for peers | +| PeerDefPreUp | string | Default peer pre-up command | +| PeerDefPostUp | string | Default peer post-up command | +| PeerDefPreDown | string | Default peer pre-down command | +| PeerDefPostDown | string | Default peer post-down command | + + +#### Peer Metrics Payload (entity: `peer_metric`) + +| JSON Field | Type | Description | +|------------|------------|----------------------------| +| Status | PeerStatus | Current status of the peer | +| Peer | Peer | Peer data | + +`PeerStatus` sub-structure: + +| JSON Field | Type | Description | +|------------------|------------|------------------------------| +| UpdatedAt | time.Time | Time of last status update | +| IsConnected | bool | Is peer currently connected | +| IsPingable | bool | Can peer be pinged | +| LastPing | *time.Time | Time of last successful ping | +| BytesReceived | uint64 | Bytes received from peer | +| BytesTransmitted | uint64 | Bytes sent to peer | +| Endpoint | string | Last known endpoint | +| LastHandshake | *time.Time | Last successful handshake | +| LastSessionStart | *time.Time | Time the last session began | + + +### Example Payloads The following payload is an example of a webhook event when a peer connects to the VPN: ```json { "event": "connect", + "entity": "peer_metric", + "identifier": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=", + "payload": { + "Status": { + "UpdatedAt": "2025-06-27T22:20:08.734900034+02:00", + "IsConnected": true, + "IsPingable": false, + "BytesReceived": 212, + "BytesTransmitted": 2884, + "Endpoint": "10.55.66.77:58756", + "LastHandshake": "2025-06-27T22:19:46.580842776+02:00", + "LastSessionStart": "2025-06-27T22:19:46.580842776+02:00" + }, + "Peer": { + "CreatedBy": "admin@wgportal.local", + "UpdatedBy": "admin@wgportal.local", + "CreatedAt": "2025-06-26T21:43:49.251839574+02:00", + "UpdatedAt": "2025-06-27T22:18:39.67763985+02:00", + "Endpoint": "10.55.66.1:51820", + "EndpointPublicKey": "eiVibpi3C2PUPcx2kwA5s09OgHx7AEaKMd33k0LQ5mM=", + "AllowedIPsStr": "10.11.12.0/24,fdfd:d3ad:c0de:1234::/64", + "ExtraAllowedIPsStr": "", + "PresharedKey": "p9DDeLUSLOdQcjS8ZsBAiqUzwDIUvTyzavRZFuzhvyE=", + "PersistentKeepalive": 16, + "DisplayName": "Peer Fb5TaziA", + "Identifier": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=", + "UserIdentifier": "admin@wgportal.local", + "InterfaceIdentifier": "wgTesting", + "AutomaticallyCreated": false, + "PrivateKey": "QBFNBe+7J49ergH0ze2TGUJMFrL/2bOL50Z2cgluYW8=", + "PublicKey": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=", + "InterfaceType": "client", + "Addresses": [ + "10.11.12.10/32", + "fdfd:d3ad:c0de:1234::a/128" + ], + "CheckAliveAddress": "", + "DnsStr": "", + "DnsSearchStr": "", + "Mtu": 1420 + } + } +} +``` + +Here is another example of a webhook event when a peer is updated: + +```json +{ + "event": "update", "entity": "peer", "identifier": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=", "payload": { - "PeerId": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=", - "IsConnected": true, - "IsPingable": false, - "LastPing": null, - "BytesReceived": 1860, - "BytesTransmitted": 10824, - "LastHandshake": "2025-06-26T23:04:33.325216659+02:00", - "Endpoint": "10.55.66.77:33874", - "LastSessionStart": "2025-06-26T22:50:40.10221606+02:00" + "CreatedBy": "admin@wgportal.local", + "UpdatedBy": "admin@wgportal.local", + "CreatedAt": "2025-06-26T21:43:49.251839574+02:00", + "UpdatedAt": "2025-06-27T22:18:39.67763985+02:00", + "Endpoint": "10.55.66.1:51820", + "EndpointPublicKey": "eiVibpi3C2PUPcx2kwA5s09OgHx7AEaKMd33k0LQ5mM=", + "AllowedIPsStr": "10.11.12.0/24,fdfd:d3ad:c0de:1234::/64", + "ExtraAllowedIPsStr": "", + "PresharedKey": "p9DDeLUSLOdQcjS8ZsBAiqUzwDIUvTyzavRZFuzhvyE=", + "PersistentKeepalive": 16, + "DisplayName": "Peer Fb5TaziA", + "Identifier": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=", + "UserIdentifier": "admin@wgportal.local", + "InterfaceIdentifier": "wgTesting", + "AutomaticallyCreated": false, + "PrivateKey": "QBFNBe+7J49ergH0ze2TGUJMFrL/2bOL50Z2cgluYW8=", + "PublicKey": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=", + "InterfaceType": "client", + "Addresses": [ + "10.11.12.10/32", + "fdfd:d3ad:c0de:1234::a/128" + ], + "CheckAliveAddress": "", + "DnsStr": "", + "DnsSearchStr": "", + "Mtu": 1420 } } ``` \ No newline at end of file diff --git a/internal/app/webhooks/manager.go b/internal/app/webhooks/manager.go index 702ac6c..b8d010c 100644 --- a/internal/app/webhooks/manager.go +++ b/internal/app/webhooks/manager.go @@ -8,6 +8,7 @@ import ( "net/http" "github.com/h44z/wg-portal/internal/app" + "github.com/h44z/wg-portal/internal/app/webhooks/models" "github.com/h44z/wg-portal/internal/config" "github.com/h44z/wg-portal/internal/domain" ) @@ -101,46 +102,46 @@ func (m Manager) sendWebhook(ctx context.Context, data io.Reader) error { } func (m Manager) handleUserCreateEvent(user domain.User) { - m.handleGenericEvent(WebhookEventCreate, user) + m.handleGenericEvent(WebhookEventCreate, models.NewUser(user)) } func (m Manager) handleUserUpdateEvent(user domain.User) { - m.handleGenericEvent(WebhookEventUpdate, user) + m.handleGenericEvent(WebhookEventUpdate, models.NewUser(user)) } func (m Manager) handleUserDeleteEvent(user domain.User) { - m.handleGenericEvent(WebhookEventDelete, user) + m.handleGenericEvent(WebhookEventDelete, models.NewUser(user)) } func (m Manager) handlePeerCreateEvent(peer domain.Peer) { - m.handleGenericEvent(WebhookEventCreate, peer) + m.handleGenericEvent(WebhookEventCreate, models.NewPeer(peer)) } func (m Manager) handlePeerUpdateEvent(peer domain.Peer) { - m.handleGenericEvent(WebhookEventUpdate, peer) + m.handleGenericEvent(WebhookEventUpdate, models.NewPeer(peer)) } func (m Manager) handlePeerDeleteEvent(peer domain.Peer) { - m.handleGenericEvent(WebhookEventDelete, peer) + m.handleGenericEvent(WebhookEventDelete, models.NewPeer(peer)) } func (m Manager) handleInterfaceCreateEvent(iface domain.Interface) { - m.handleGenericEvent(WebhookEventCreate, iface) + m.handleGenericEvent(WebhookEventCreate, models.NewInterface(iface)) } func (m Manager) handleInterfaceUpdateEvent(iface domain.Interface) { - m.handleGenericEvent(WebhookEventUpdate, iface) + m.handleGenericEvent(WebhookEventUpdate, models.NewInterface(iface)) } func (m Manager) handleInterfaceDeleteEvent(iface domain.Interface) { - m.handleGenericEvent(WebhookEventDelete, iface) + m.handleGenericEvent(WebhookEventDelete, models.NewInterface(iface)) } -func (m Manager) handlePeerStateChangeEvent(peerStatus domain.PeerStatus) { +func (m Manager) handlePeerStateChangeEvent(peerStatus domain.PeerStatus, peer domain.Peer) { if peerStatus.IsConnected { - m.handleGenericEvent(WebhookEventConnect, peerStatus) + m.handleGenericEvent(WebhookEventConnect, models.NewPeerMetrics(peerStatus, peer)) } else { - m.handleGenericEvent(WebhookEventDisconnect, peerStatus) + m.handleGenericEvent(WebhookEventDisconnect, models.NewPeerMetrics(peerStatus, peer)) } } @@ -177,18 +178,18 @@ func (m Manager) createWebhookData(action WebhookEvent, payload any) (*WebhookDa } switch v := payload.(type) { - case domain.User: + case models.User: d.Entity = WebhookEntityUser - d.Identifier = string(v.Identifier) - case domain.Peer: + d.Identifier = v.Identifier + case models.Peer: d.Entity = WebhookEntityPeer - d.Identifier = string(v.Identifier) - case domain.Interface: + d.Identifier = v.Identifier + case models.Interface: d.Entity = WebhookEntityInterface - d.Identifier = string(v.Identifier) - case domain.PeerStatus: - d.Entity = WebhookEntityPeer - d.Identifier = string(v.PeerId) + d.Identifier = v.Identifier + case models.PeerMetrics: + d.Entity = WebhookEntityPeerMetric + d.Identifier = v.Peer.Identifier default: return nil, fmt.Errorf("unsupported payload type: %T", v) } diff --git a/internal/app/webhooks/model.go b/internal/app/webhooks/model.go index b0ca9a5..c806d47 100644 --- a/internal/app/webhooks/model.go +++ b/internal/app/webhooks/model.go @@ -34,9 +34,10 @@ func (d *WebhookData) Serialize() (io.Reader, error) { type WebhookEntity = string const ( - WebhookEntityUser WebhookEntity = "user" - WebhookEntityPeer WebhookEntity = "peer" - WebhookEntityInterface WebhookEntity = "interface" + WebhookEntityUser WebhookEntity = "user" + WebhookEntityPeer WebhookEntity = "peer" + WebhookEntityPeerMetric WebhookEntity = "peer_metric" + WebhookEntityInterface WebhookEntity = "interface" ) type WebhookEvent = string diff --git a/internal/app/webhooks/models/interface.go b/internal/app/webhooks/models/interface.go new file mode 100644 index 0000000..c3a0eea --- /dev/null +++ b/internal/app/webhooks/models/interface.go @@ -0,0 +1,99 @@ +package models + +import ( + "time" + + "github.com/h44z/wg-portal/internal/domain" +) + +// Interface represents an interface model for webhooks. For details about the fields, see the domain.Interface struct. +type Interface struct { + CreatedBy string `json:"CreatedBy"` + UpdatedBy string `json:"UpdatedBy"` + CreatedAt time.Time `json:"CreatedAt"` + UpdatedAt time.Time `json:"UpdatedAt"` + + Identifier string `json:"Identifier"` + PrivateKey string `json:"PrivateKey"` + PublicKey string `json:"PublicKey"` + ListenPort int `json:"ListenPort"` + + Addresses []string `json:"Addresses"` + DnsStr string `json:"DnsStr"` + DnsSearchStr string `json:"DnsSearchStr"` + + Mtu int `json:"Mtu"` + FirewallMark uint32 `json:"FirewallMark"` + RoutingTable string `json:"RoutingTable"` + + PreUp string `json:"PreUp"` + PostUp string `json:"PostUp"` + PreDown string `json:"PreDown"` + PostDown string `json:"PostDown"` + + SaveConfig bool `json:"SaveConfig"` + + DisplayName string `json:"DisplayName"` + Type string `json:"Type"` + DriverType string `json:"DriverType"` + Disabled *time.Time `json:"Disabled,omitempty"` + DisabledReason string `json:"DisabledReason,omitempty"` + + PeerDefNetworkStr string `json:"PeerDefNetworkStr,omitempty"` + PeerDefDnsStr string `json:"PeerDefDnsStr,omitempty"` + PeerDefDnsSearchStr string `json:"PeerDefDnsSearchStr,omitempty"` + PeerDefEndpoint string `json:"PeerDefEndpoint,omitempty"` + PeerDefAllowedIPsStr string `json:"PeerDefAllowedIPsStr,omitempty"` + PeerDefMtu int `json:"PeerDefMtu,omitempty"` + PeerDefPersistentKeepalive int `json:"PeerDefPersistentKeepalive,omitempty"` + PeerDefFirewallMark uint32 `json:"PeerDefFirewallMark,omitempty"` + PeerDefRoutingTable string `json:"PeerDefRoutingTable,omitempty"` + + PeerDefPreUp string `json:"PeerDefPreUp,omitempty"` + PeerDefPostUp string `json:"PeerDefPostUp,omitempty"` + PeerDefPreDown string `json:"PeerDefPreDown,omitempty"` + PeerDefPostDown string `json:"PeerDefPostDown,omitempty"` +} + +// NewInterface creates a new Interface model from a domain.Interface. +func NewInterface(src domain.Interface) Interface { + return Interface{ + CreatedBy: src.CreatedBy, + UpdatedBy: src.UpdatedBy, + CreatedAt: src.CreatedAt, + UpdatedAt: src.UpdatedAt, + Identifier: string(src.Identifier), + PrivateKey: src.KeyPair.PrivateKey, + PublicKey: src.KeyPair.PublicKey, + ListenPort: src.ListenPort, + Addresses: domain.CidrsToStringSlice(src.Addresses), + DnsStr: src.DnsStr, + DnsSearchStr: src.DnsSearchStr, + Mtu: src.Mtu, + FirewallMark: src.FirewallMark, + RoutingTable: src.RoutingTable, + PreUp: src.PreUp, + PostUp: src.PostUp, + PreDown: src.PreDown, + PostDown: src.PostDown, + SaveConfig: src.SaveConfig, + DisplayName: string(src.Identifier), + Type: string(src.Type), + DriverType: src.DriverType, + Disabled: src.Disabled, + DisabledReason: src.DisabledReason, + PeerDefNetworkStr: src.PeerDefNetworkStr, + PeerDefDnsStr: src.PeerDefDnsStr, + PeerDefDnsSearchStr: src.PeerDefDnsSearchStr, + PeerDefEndpoint: src.PeerDefEndpoint, + PeerDefAllowedIPsStr: src.PeerDefAllowedIPsStr, + PeerDefMtu: src.PeerDefMtu, + PeerDefPersistentKeepalive: src.PeerDefPersistentKeepalive, + PeerDefFirewallMark: src.PeerDefFirewallMark, + PeerDefRoutingTable: src.PeerDefRoutingTable, + PeerDefPreUp: src.PeerDefPreUp, + PeerDefPostUp: src.PeerDefPostUp, + PeerDefPreDown: src.PeerDefPreDown, + PeerDefPostDown: src.PeerDefPostDown, + } +} diff --git a/internal/app/webhooks/models/peer.go b/internal/app/webhooks/models/peer.go new file mode 100644 index 0000000..c7a5919 --- /dev/null +++ b/internal/app/webhooks/models/peer.go @@ -0,0 +1,89 @@ +package models + +import ( + "time" + + "github.com/h44z/wg-portal/internal/domain" +) + +// Peer represents a peer model for webhooks. For details about the fields, see the domain.Peer struct. +type Peer struct { + CreatedBy string `json:"CreatedBy"` + UpdatedBy string `json:"UpdatedBy"` + CreatedAt time.Time `json:"CreatedAt"` + UpdatedAt time.Time `json:"UpdatedAt"` + + Endpoint string `json:"Endpoint"` + EndpointPublicKey string `json:"EndpointPublicKey"` + AllowedIPsStr string `json:"AllowedIPsStr"` + ExtraAllowedIPsStr string `json:"ExtraAllowedIPsStr"` + PresharedKey string `json:"PresharedKey"` + PersistentKeepalive int `json:"PersistentKeepalive"` + + DisplayName string `json:"DisplayName"` + Identifier string `json:"Identifier"` + UserIdentifier string `json:"UserIdentifier"` + InterfaceIdentifier string `json:"InterfaceIdentifier"` + Disabled *time.Time `json:"Disabled,omitempty"` + DisabledReason string `json:"DisabledReason,omitempty"` + ExpiresAt *time.Time `json:"ExpiresAt,omitempty"` + Notes string `json:"Notes,omitempty"` + AutomaticallyCreated bool `json:"AutomaticallyCreated"` + + PrivateKey string `json:"PrivateKey"` + PublicKey string `json:"PublicKey"` + + InterfaceType string `json:"InterfaceType"` + + Addresses []string `json:"Addresses"` + CheckAliveAddress string `json:"CheckAliveAddress"` + DnsStr string `json:"DnsStr"` + DnsSearchStr string `json:"DnsSearchStr"` + Mtu int `json:"Mtu"` + FirewallMark uint32 `json:"FirewallMark,omitempty"` + RoutingTable string `json:"RoutingTable,omitempty"` + + PreUp string `json:"PreUp,omitempty"` + PostUp string `json:"PostUp,omitempty"` + PreDown string `json:"PreDown,omitempty"` + PostDown string `json:"PostDown,omitempty"` +} + +// NewPeer creates a new Peer model from a domain.Peer. +func NewPeer(src domain.Peer) Peer { + return Peer{ + CreatedBy: src.CreatedBy, + UpdatedBy: src.UpdatedBy, + CreatedAt: src.CreatedAt, + UpdatedAt: src.UpdatedAt, + Endpoint: src.Endpoint.GetValue(), + EndpointPublicKey: src.EndpointPublicKey.GetValue(), + AllowedIPsStr: src.AllowedIPsStr.GetValue(), + ExtraAllowedIPsStr: src.ExtraAllowedIPsStr, + PresharedKey: string(src.PresharedKey), + PersistentKeepalive: src.PersistentKeepalive.GetValue(), + DisplayName: src.DisplayName, + Identifier: string(src.Identifier), + UserIdentifier: string(src.UserIdentifier), + InterfaceIdentifier: string(src.InterfaceIdentifier), + Disabled: src.Disabled, + DisabledReason: src.DisabledReason, + ExpiresAt: src.ExpiresAt, + Notes: src.Notes, + AutomaticallyCreated: src.AutomaticallyCreated, + PrivateKey: src.Interface.KeyPair.PrivateKey, + PublicKey: src.Interface.KeyPair.PublicKey, + InterfaceType: string(src.Interface.Type), + Addresses: domain.CidrsToStringSlice(src.Interface.Addresses), + CheckAliveAddress: src.Interface.CheckAliveAddress, + DnsStr: src.Interface.DnsStr.GetValue(), + DnsSearchStr: src.Interface.DnsSearchStr.GetValue(), + Mtu: src.Interface.Mtu.GetValue(), + FirewallMark: src.Interface.FirewallMark.GetValue(), + RoutingTable: src.Interface.RoutingTable.GetValue(), + PreUp: src.Interface.PreUp.GetValue(), + PostUp: src.Interface.PostUp.GetValue(), + PreDown: src.Interface.PreDown.GetValue(), + PostDown: src.Interface.PostDown.GetValue(), + } +} diff --git a/internal/app/webhooks/models/peer_metrics.go b/internal/app/webhooks/models/peer_metrics.go new file mode 100644 index 0000000..f380d2c --- /dev/null +++ b/internal/app/webhooks/models/peer_metrics.go @@ -0,0 +1,50 @@ +package models + +import ( + "time" + + "github.com/h44z/wg-portal/internal/domain" +) + +// PeerMetrics represents a peer metrics model for webhooks. +// For details about the fields, see the domain.PeerStatus and domain.Peer structs. +type PeerMetrics struct { + Status PeerStatus `json:"Status"` + Peer Peer `json:"Peer"` +} + +// PeerStatus represents the status of a peer for webhooks. +// For details about the fields, see the domain.PeerStatus struct. +type PeerStatus struct { + UpdatedAt time.Time `json:"UpdatedAt"` + + IsConnected bool `json:"IsConnected"` + + IsPingable bool `json:"IsPingable"` + LastPing *time.Time `json:"LastPing,omitempty"` + + BytesReceived uint64 `json:"BytesReceived"` + BytesTransmitted uint64 `json:"BytesTransmitted"` + + Endpoint string `json:"Endpoint"` + LastHandshake *time.Time `json:"LastHandshake,omitempty"` + LastSessionStart *time.Time `json:"LastSessionStart,omitempty"` +} + +// NewPeerMetrics creates a new PeerMetrics model from the domain.PeerStatus and domain.Peer models. +func NewPeerMetrics(status domain.PeerStatus, peer domain.Peer) PeerMetrics { + return PeerMetrics{ + Status: PeerStatus{ + UpdatedAt: status.UpdatedAt, + IsConnected: status.IsConnected, + IsPingable: status.IsPingable, + LastPing: status.LastPing, + BytesReceived: status.BytesReceived, + BytesTransmitted: status.BytesTransmitted, + Endpoint: status.Endpoint, + LastHandshake: status.LastHandshake, + LastSessionStart: status.LastSessionStart, + }, + Peer: NewPeer(peer), + } +} diff --git a/internal/app/webhooks/models/user.go b/internal/app/webhooks/models/user.go new file mode 100644 index 0000000..defe962 --- /dev/null +++ b/internal/app/webhooks/models/user.go @@ -0,0 +1,56 @@ +package models + +import ( + "time" + + "github.com/h44z/wg-portal/internal/domain" +) + +// User represents a user model for webhooks. For details about the fields, see the domain.User struct. +type User struct { + CreatedBy string `json:"CreatedBy"` + UpdatedBy string `json:"UpdatedBy"` + CreatedAt time.Time `json:"CreatedAt"` + UpdatedAt time.Time `json:"UpdatedAt"` + + Identifier string `json:"Identifier"` + Email string `json:"Email"` + Source string `json:"Source"` + ProviderName string `json:"ProviderName"` + IsAdmin bool `json:"IsAdmin"` + + Firstname string `json:"Firstname,omitempty"` + Lastname string `json:"Lastname,omitempty"` + Phone string `json:"Phone,omitempty"` + Department string `json:"Department,omitempty"` + Notes string `json:"Notes,omitempty"` + + Disabled *time.Time `json:"Disabled,omitempty"` + DisabledReason string `json:"DisabledReason,omitempty"` + Locked *time.Time `json:"Locked,omitempty"` + LockedReason string `json:"LockedReason,omitempty"` +} + +// NewUser creates a new User model from a domain.User +func NewUser(src domain.User) User { + return User{ + CreatedBy: src.CreatedBy, + UpdatedBy: src.UpdatedBy, + CreatedAt: src.CreatedAt, + UpdatedAt: src.UpdatedAt, + Identifier: string(src.Identifier), + Email: src.Email, + Source: string(src.Source), + ProviderName: src.ProviderName, + IsAdmin: src.IsAdmin, + Firstname: src.Firstname, + Lastname: src.Lastname, + Phone: src.Phone, + Department: src.Department, + Notes: src.Notes, + Disabled: src.Disabled, + DisabledReason: src.DisabledReason, + Locked: src.Locked, + LockedReason: src.LockedReason, + } +} diff --git a/internal/app/wireguard/statistics.go b/internal/app/wireguard/statistics.go index 2733468..dcc8b36 100644 --- a/internal/app/wireguard/statistics.go +++ b/internal/app/wireguard/statistics.go @@ -213,8 +213,14 @@ func (c *StatisticsCollector) collectPeerData(ctx context.Context) { } if connectionStateChanged { + peerModel, err := c.db.GetPeer(ctx, peer.Identifier) + if err != nil { + slog.Error("failed to fetch peer for data collection", "peer", peer.Identifier, "error", + err) + continue + } // publish event if connection state changed - c.bus.Publish(app.TopicPeerStateChanged, newPeerStatus) + c.bus.Publish(app.TopicPeerStateChanged, newPeerStatus, *peerModel) } } } @@ -356,7 +362,7 @@ func (c *StatisticsCollector) pingWorker(ctx context.Context) { if connectionStateChanged { // publish event if connection state changed - c.bus.Publish(app.TopicPeerStateChanged, newPeerStatus) + c.bus.Publish(app.TopicPeerStateChanged, newPeerStatus, peer) } } } From f2868409641fc0ce28ac140c7f0fb94d10d61d0a Mon Sep 17 00:00:00 2001 From: h44z Date: Sun, 29 Jun 2025 20:00:15 +0200 Subject: [PATCH 15/22] fix oauth domain check (#474) (#476) --- internal/app/auth/auth.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/app/auth/auth.go b/internal/app/auth/auth.go index 380fe81..0ff8d9e 100644 --- a/internal/app/auth/auth.go +++ b/internal/app/auth/auth.go @@ -434,6 +434,10 @@ func (a *Authenticator) OauthLoginStep2(ctx context.Context, providerId, nonce, return nil, fmt.Errorf("unable to parse user information: %w", err) } + if !isDomainAllowed(userInfo.Email, oauthProvider.GetAllowedDomains()) { + return nil, fmt.Errorf("user %s is not in allowed domains", userInfo.Email) + } + ctx = domain.SetUserInfo(ctx, domain.SystemAdminContextUserInfo()) // switch to admin user context to check if user exists user, err := a.processUserInfo(ctx, userInfo, domain.UserSourceOauth, oauthProvider.GetName(), @@ -450,10 +454,6 @@ func (a *Authenticator) OauthLoginStep2(ctx context.Context, providerId, nonce, return nil, fmt.Errorf("unable to process user information: %w", err) } - if !isDomainAllowed(userInfo.Email, oauthProvider.GetAllowedDomains()) { - return nil, fmt.Errorf("user is not in allowed domains: %w", err) - } - if user.IsLocked() || user.IsDisabled() { a.bus.Publish(app.TopicAuditLoginFailed, domain.AuditEventWrapper[audit.AuthEvent]{ Ctx: ctx, From a7bd3b3f9556dfee06b7663a7e2d78328bc245eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Jul 2025 22:20:23 +0200 Subject: [PATCH 16/22] chore(deps): bump github.com/go-playground/validator/v10 (#480) Bumps [github.com/go-playground/validator/v10](https://github.com/go-playground/validator) from 10.26.0 to 10.27.0. - [Release notes](https://github.com/go-playground/validator/releases) - [Commits](https://github.com/go-playground/validator/compare/v10.26.0...v10.27.0) --- updated-dependencies: - dependency-name: github.com/go-playground/validator/v10 dependency-version: 10.27.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1f2e60c..680a605 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/glebarez/sqlite v1.11.0 github.com/go-ldap/ldap/v3 v3.4.11 github.com/go-pkgz/routegroup v1.4.1 - github.com/go-playground/validator/v10 v10.26.0 + github.com/go-playground/validator/v10 v10.27.0 github.com/go-webauthn/webauthn v0.13.0 github.com/google/uuid v1.6.0 github.com/prometheus-community/pro-bing v0.7.0 diff --git a/go.sum b/go.sum index 4b64484..1f35462 100644 --- a/go.sum +++ b/go.sum @@ -70,8 +70,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= -github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= +github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= From a6d985d3ce97dddc71ebdf9d3f42c03a127571b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Jul 2025 22:36:11 +0200 Subject: [PATCH 17/22] chore(deps): bump the patch group across 1 directory with 4 updates (#485) Bumps the patch group with 2 updates in the / directory: [github.com/go-webauthn/webauthn](https://github.com/go-webauthn/webauthn) and [github.com/swaggo/swag](https://github.com/swaggo/swag). Updates `github.com/go-webauthn/webauthn` from 0.13.0 to 0.13.4 - [Release notes](https://github.com/go-webauthn/webauthn/releases) - [Commits](https://github.com/go-webauthn/webauthn/compare/v0.13.0...v0.13.4) Updates `github.com/swaggo/swag` from 1.16.4 to 1.16.5 - [Release notes](https://github.com/swaggo/swag/releases) - [Changelog](https://github.com/swaggo/swag/blob/master/.goreleaser.yml) - [Commits](https://github.com/swaggo/swag/compare/v1.16.4...v1.16.5) Updates `golang.org/x/crypto` from 0.39.0 to 0.40.0 - [Commits](https://github.com/golang/crypto/compare/v0.39.0...v0.40.0) Updates `golang.org/x/sys` from 0.33.0 to 0.34.0 - [Commits](https://github.com/golang/sys/compare/v0.33.0...v0.34.0) --- updated-dependencies: - dependency-name: github.com/go-webauthn/webauthn dependency-version: 0.13.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch - dependency-name: github.com/swaggo/swag dependency-version: 1.16.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch - dependency-name: golang.org/x/crypto dependency-version: 0.40.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: patch - dependency-name: golang.org/x/sys dependency-version: 0.34.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 23 ++++++++++++----------- go.sum | 44 ++++++++++++++++++++++---------------------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index 680a605..fa7499f 100644 --- a/go.mod +++ b/go.mod @@ -10,20 +10,20 @@ require ( github.com/go-ldap/ldap/v3 v3.4.11 github.com/go-pkgz/routegroup v1.4.1 github.com/go-playground/validator/v10 v10.27.0 - github.com/go-webauthn/webauthn v0.13.0 + github.com/go-webauthn/webauthn v0.13.4 github.com/google/uuid v1.6.0 github.com/prometheus-community/pro-bing v0.7.0 github.com/prometheus/client_golang v1.22.0 github.com/stretchr/testify v1.10.0 - github.com/swaggo/swag v1.16.4 + github.com/swaggo/swag v1.16.5 github.com/vardius/message-bus v1.1.5 github.com/vishvananda/netlink v1.3.1 github.com/xhit/go-simple-mail/v2 v2.16.0 github.com/yeqown/go-qrcode/v2 v2.2.5 github.com/yeqown/go-qrcode/writer/compressed v1.0.1 - golang.org/x/crypto v0.39.0 + golang.org/x/crypto v0.40.0 golang.org/x/oauth2 v0.30.0 - golang.org/x/sys v0.33.0 + golang.org/x/sys v0.34.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.6.0 @@ -40,7 +40,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/fxamacker/cbor/v2 v2.8.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/gabriel-vasile/mimetype v1.4.9 // indirect github.com/glebarez/go-sqlite v1.22.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect @@ -53,8 +53,8 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-sql-driver/mysql v1.9.2 // indirect github.com/go-test/deep v1.1.1 // indirect - github.com/go-webauthn/x v0.1.21 // indirect - github.com/golang-jwt/jwt/v5 v5.2.2 // indirect + github.com/go-webauthn/x v0.1.23 // indirect + github.com/golang-jwt/jwt/v5 v5.2.3 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/google/go-cmp v0.7.0 // indirect @@ -87,10 +87,11 @@ require ( github.com/x448/float16 v0.8.4 // indirect github.com/yeqown/reedsolomon v1.0.0 // indirect golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect - golang.org/x/net v0.40.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/text v0.26.0 // indirect - golang.org/x/tools v0.33.0 // indirect + golang.org/x/mod v0.25.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/text v0.27.0 // indirect + golang.org/x/tools v0.34.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect google.golang.org/protobuf v1.36.6 // indirect modernc.org/libc v1.63.0 // indirect diff --git a/go.sum b/go.sum index 1f35462..9b9a87b 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/ github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= -github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= @@ -76,15 +76,15 @@ github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRj github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-webauthn/webauthn v0.13.0 h1:cJIL1/1l+22UekVhipziAaSgESJxokYkowUqAIsWs0Y= -github.com/go-webauthn/webauthn v0.13.0/go.mod h1:Oy9o2o79dbLKRPZWWgRIOdtBGAhKnDIaBp2PFkICRHs= -github.com/go-webauthn/x v0.1.21 h1:nFbckQxudvHEJn2uy1VEi713MeSpApoAv9eRqsb9AdQ= -github.com/go-webauthn/x v0.1.21/go.mod h1:sEYohtg1zL4An1TXIUIQ5csdmoO+WO0R4R2pGKaHYKA= +github.com/go-webauthn/webauthn v0.13.4 h1:q68qusWPcqHbg9STSxBLBHnsKaLxNO0RnVKaAqMuAuQ= +github.com/go-webauthn/webauthn v0.13.4/go.mod h1:MglN6OH9ECxvhDqoq1wMoF6P6JRYDiQpC9nc5OomQmI= +github.com/go-webauthn/x v0.1.23 h1:9lEO0s+g8iTyz5Vszlg/rXTGrx3CjcD0RZQ1GPZCaxI= +github.com/go-webauthn/x v0.1.23/go.mod h1:AJd3hI7NfEp/4fI6T4CHD753u91l510lglU7/NMN6+E= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= -github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= +github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -197,8 +197,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= -github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= +github.com/swaggo/swag v1.16.5 h1:nMf2fEV1TetMTJb4XzD0Lz7jFfKJmJKGTygEey8NSxM= +github.com/swaggo/swag v1.16.5/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg= github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns= github.com/toorop/go-dkim v0.0.0-20250226130143-9025cce95817 h1:q0hKh5a5FRkhuTb5JNfgjzpzvYLHjH0QOgPZPYnRWGA= github.com/toorop/go-dkim v0.0.0-20250226130143-9025cce95817/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns= @@ -228,8 +228,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -252,8 +252,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -263,8 +263,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -285,8 +285,8 @@ golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -305,16 +305,16 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= 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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= From 1794b8653a99124e3cb3303360ab1c9699409eca Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Sat, 19 Jul 2025 23:29:05 +0200 Subject: [PATCH 18/22] add retry handling for auth provider setup (#484) --- cmd/wg-portal/main.go | 1 + internal/app/auth/auth.go | 118 ++++++++++++++++++++++++++++---------- 2 files changed, 88 insertions(+), 31 deletions(-) diff --git a/cmd/wg-portal/main.go b/cmd/wg-portal/main.go index dbd2020..0c1dd20 100644 --- a/cmd/wg-portal/main.go +++ b/cmd/wg-portal/main.go @@ -87,6 +87,7 @@ func main() { authenticator, err := auth.NewAuthenticator(&cfg.Auth, cfg.Web.ExternalUrl, eventBus, userManager) internal.AssertNoError(err) + authenticator.StartBackgroundJobs(ctx) webAuthn, err := auth.NewWebAuthnAuthenticator(cfg, eventBus, userManager) internal.AssertNoError(err) diff --git a/internal/app/auth/auth.go b/internal/app/auth/auth.go index 0ff8d9e..c6e5232 100644 --- a/internal/app/auth/auth.go +++ b/internal/app/auth/auth.go @@ -93,6 +93,8 @@ type Authenticator struct { // URL prefix for the callback endpoints, this is a combination of the external URL and the API prefix callbackUrlPrefix string + callbackUrl *url.URL + users UserManager } @@ -102,82 +104,136 @@ func NewAuthenticator(cfg *config.Auth, extUrl string, bus EventBus, users UserM error, ) { a := &Authenticator{ - cfg: cfg, - bus: bus, - users: users, - callbackUrlPrefix: fmt.Sprintf("%s/api/v0", extUrl), + cfg: cfg, + bus: bus, + users: users, + callbackUrlPrefix: fmt.Sprintf("%s/api/v0", extUrl), + oauthAuthenticators: make(map[string]AuthenticatorOauth, len(cfg.OpenIDConnect)+len(cfg.OAuth)), + ldapAuthenticators: make(map[string]AuthenticatorLdap, len(cfg.Ldap)), } - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - err := a.setupExternalAuthProviders(ctx) + parsedExtUrl, err := url.Parse(a.callbackUrlPrefix) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to parse external URL: %w", err) } + a.callbackUrl = parsedExtUrl return a, nil } -func (a *Authenticator) setupExternalAuthProviders(ctx context.Context) error { - extUrl, err := url.Parse(a.callbackUrlPrefix) - if err != nil { - return fmt.Errorf("failed to parse external url: %w", err) - } +// StartBackgroundJobs starts the background jobs for the authenticator. +// It sets up the external authentication providers (OIDC, OAuth, LDAP) and retries in case of errors. +func (a *Authenticator) StartBackgroundJobs(ctx context.Context) { + go func() { + // Initialize local copies of authentication providers to allow retry in case of errors + oidcQueue := a.cfg.OpenIDConnect + oauthQueue := a.cfg.OAuth + ldapQueue := a.cfg.Ldap - a.oauthAuthenticators = make(map[string]AuthenticatorOauth, len(a.cfg.OpenIDConnect)+len(a.cfg.OAuth)) - a.ldapAuthenticators = make(map[string]AuthenticatorLdap, len(a.cfg.Ldap)) + ticker := time.NewTicker(30 * time.Second) // Ticker for delay between retries + defer ticker.Stop() - for i := range a.cfg.OpenIDConnect { // OIDC - providerCfg := &a.cfg.OpenIDConnect[i] + for { + select { + case <-ticker.C: + failedOidc, failedOauth, failedLdap := a.setupExternalAuthProviders(oidcQueue, oauthQueue, ldapQueue) + if len(failedOidc) > 0 || len(failedOauth) > 0 || len(failedLdap) > 0 { + slog.Warn("failed to setup some external auth providers, retrying in 30 seconds", + "failedOidc", len(failedOidc), "failedOauth", len(failedOauth), "failedLdap", len(failedLdap)) + // Retry failed providers + oidcQueue = failedOidc + oauthQueue = failedOauth + ldapQueue = failedLdap + } else { + slog.Info("successfully setup all external auth providers") + return // Exit goroutine if all providers are set up successfully + } + case <-ctx.Done(): + slog.Info("context cancelled, stopping setup of external auth providers") + return // Exit goroutine if context is cancelled + } + } + }() +} + +func (a *Authenticator) setupExternalAuthProviders( + oidc []config.OpenIDConnectProvider, + oauth []config.OAuthProvider, + ldap []config.LdapProvider, +) ( + []config.OpenIDConnectProvider, + []config.OAuthProvider, + []config.LdapProvider, +) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + var failedOidc []config.OpenIDConnectProvider + var failedOauth []config.OAuthProvider + var failedLdap []config.LdapProvider + + for i := range oidc { // OIDC + providerCfg := &oidc[i] providerId := strings.ToLower(providerCfg.ProviderName) if _, exists := a.oauthAuthenticators[providerId]; exists { - return fmt.Errorf("auth provider with name %s is already registerd", providerId) + // this is an unrecoverable error, we cannot register the same provider twice + slog.Error("OIDC auth provider is already registered", "name", providerId) + continue // skip this provider } - redirectUrl := *extUrl + redirectUrl := *a.callbackUrl redirectUrl.Path = path.Join(redirectUrl.Path, "/auth/login/", providerId, "/callback") provider, err := newOidcAuthenticator(ctx, redirectUrl.String(), providerCfg) if err != nil { - return fmt.Errorf("failed to setup oidc authentication provider %s: %w", providerCfg.ProviderName, err) + failedOidc = append(failedOidc, oidc[i]) + slog.Error("failed to setup oidc authentication provider", "name", providerId, "error", err) + continue } a.oauthAuthenticators[providerId] = provider } - for i := range a.cfg.OAuth { // PLAIN OAUTH - providerCfg := &a.cfg.OAuth[i] + for i := range oauth { // PLAIN OAUTH + providerCfg := &oauth[i] providerId := strings.ToLower(providerCfg.ProviderName) if _, exists := a.oauthAuthenticators[providerId]; exists { - return fmt.Errorf("auth provider with name %s is already registerd", providerId) + // this is an unrecoverable error, we cannot register the same provider twice + slog.Error("OAUTH auth provider is already registered", "name", providerId) + continue // skip this provider } - redirectUrl := *extUrl + redirectUrl := *a.callbackUrl redirectUrl.Path = path.Join(redirectUrl.Path, "/auth/login/", providerId, "/callback") provider, err := newPlainOauthAuthenticator(ctx, redirectUrl.String(), providerCfg) if err != nil { - return fmt.Errorf("failed to setup oauth authentication provider %s: %w", providerId, err) + failedOauth = append(failedOauth, oauth[i]) + slog.Error("failed to setup oauth authentication provider", "name", providerId, "error", err) + continue } a.oauthAuthenticators[providerId] = provider } - for i := range a.cfg.Ldap { // LDAP - providerCfg := &a.cfg.Ldap[i] + for i := range ldap { // LDAP + providerCfg := &ldap[i] providerId := strings.ToLower(providerCfg.URL) if _, exists := a.ldapAuthenticators[providerId]; exists { - return fmt.Errorf("auth provider with name %s is already registerd", providerId) + // this is an unrecoverable error, we cannot register the same provider twice + slog.Error("LDAP auth provider is already registered", "name", providerId) + continue // skip this provider } provider, err := newLdapAuthenticator(ctx, providerCfg) if err != nil { - return fmt.Errorf("failed to setup ldap authentication provider %s: %w", providerId, err) + failedLdap = append(failedLdap, ldap[i]) + slog.Error("failed to setup ldap authentication provider", "name", providerId, "error", err) + continue } a.ldapAuthenticators[providerId] = provider } - return nil + return failedOidc, failedOauth, failedLdap } // GetExternalLoginProviders returns a list of all available external login providers. From dc002b156b114baaad5ddcc92e06b750c360ee4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Jul 2025 12:58:07 +0200 Subject: [PATCH 19/22] chore(deps): bump github.com/alexedwards/scs/v2 from 2.8.0 to 2.9.0 (#487) Bumps [github.com/alexedwards/scs/v2](https://github.com/alexedwards/scs) from 2.8.0 to 2.9.0. - [Release notes](https://github.com/alexedwards/scs/releases) - [Commits](https://github.com/alexedwards/scs/compare/v2.8.0...v2.9.0) --- updated-dependencies: - dependency-name: github.com/alexedwards/scs/v2 dependency-version: 2.9.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fa7499f..c3c9ab0 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.0 require ( github.com/a8m/envsubst v1.4.3 - github.com/alexedwards/scs/v2 v2.8.0 + github.com/alexedwards/scs/v2 v2.9.0 github.com/coreos/go-oidc/v3 v3.14.1 github.com/glebarez/sqlite v1.11.0 github.com/go-ldap/ldap/v3 v3.4.11 diff --git a/go.sum b/go.sum index 9b9a87b..ea9ed83 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/a8m/envsubst v1.4.3 h1:kDF7paGK8QACWYaQo6KtyYBozY2jhQrTuNNuUxQkhJY= github.com/a8m/envsubst v1.4.3/go.mod h1:4jjHWQlZoaXPoLQUb7H2qT4iLkZDdmEQiOUogdUmqVU= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw= -github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8= +github.com/alexedwards/scs/v2 v2.9.0 h1:xa05mVpwTBm1iLeTMNFfAWpKUm4fXAW7CeAViqBVS90= +github.com/alexedwards/scs/v2 v2.9.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= From ffef1f7b1246899d83af627fa399e0656d6e4eff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Jul 2025 22:28:52 +0200 Subject: [PATCH 20/22] chore(deps): bump gorm.io/driver/sqlserver in the gorm group (#488) Bumps the gorm group with 1 update: [gorm.io/driver/sqlserver](https://github.com/go-gorm/sqlserver). Updates `gorm.io/driver/sqlserver` from 1.6.0 to 1.6.1 - [Commits](https://github.com/go-gorm/sqlserver/compare/v1.6.0...v1.6.1) --- updated-dependencies: - dependency-name: gorm.io/driver/sqlserver dependency-version: 1.6.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: gorm ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 +-- go.sum | 102 +++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 65 insertions(+), 41 deletions(-) diff --git a/go.mod b/go.mod index c3c9ab0..dfa6bbf 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.6.0 gorm.io/driver/postgres v1.6.0 - gorm.io/driver/sqlserver v1.6.0 + gorm.io/driver/sqlserver v1.6.1 gorm.io/gorm v1.30.0 ) @@ -73,7 +73,7 @@ require ( github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.5.1 // indirect - github.com/microsoft/go-mssqldb v1.8.0 // indirect + github.com/microsoft/go-mssqldb v1.8.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect diff --git a/go.sum b/go.sum index ea9ed83..d905e33 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,14 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.2/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 h1:jBQA3cKT4L2rWMpgE7Yt3Hwh2aUj8KXjIGLxjHeYNNo= github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= @@ -16,7 +17,7 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= @@ -33,6 +34,7 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk= github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -80,12 +82,11 @@ github.com/go-webauthn/webauthn v0.13.4 h1:q68qusWPcqHbg9STSxBLBHnsKaLxNO0RnVKaA github.com/go-webauthn/webauthn v0.13.4/go.mod h1:MglN6OH9ECxvhDqoq1wMoF6P6JRYDiQpC9nc5OomQmI= github.com/go-webauthn/x v0.1.23 h1:9lEO0s+g8iTyz5Vszlg/rXTGrx3CjcD0RZQ1GPZCaxI= github.com/go-webauthn/x v0.1.23/go.mod h1:AJd3hI7NfEp/4fI6T4CHD753u91l510lglU7/NMN6+E= -github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= @@ -98,7 +99,6 @@ github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU= github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -119,12 +119,10 @@ github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFK github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= -github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= @@ -139,8 +137,11 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -157,23 +158,22 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/ github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/microsoft/go-mssqldb v0.19.0/go.mod h1:ukJCBnnzLzpVF0qYRT+eg1e+eSwjeQ7IvenUv8QPook= -github.com/microsoft/go-mssqldb v1.8.0 h1:7cyZ/AT7ycDsEoWPIXibd+aVKFtteUNhDGf3aobP+tw= -github.com/microsoft/go-mssqldb v1.8.0/go.mod h1:6znkekS3T2vp0waiMhen4GPU1BiAsrP+iXHcE7a7rFo= +github.com/microsoft/go-mssqldb v1.8.2 h1:236sewazvC8FvG6Dr3bszrVhMkAl4KYImryLkRMCd0I= +github.com/microsoft/go-mssqldb v1.8.2/go.mod h1:vp38dT33FGfVotRiTmDo3bFyaHq+p3LektQrjTULowo= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus-community/pro-bing v0.7.0 h1:KFYFbxC2f2Fp6c+TyxbCOEarf7rbnzr9Gw8eIb0RfZA= @@ -188,13 +188,21 @@ github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2b github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/swaggo/swag v1.16.5 h1:nMf2fEV1TetMTJb4XzD0Lz7jFfKJmJKGTygEey8NSxM= @@ -220,38 +228,46 @@ github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= @@ -266,44 +282,54 @@ golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= @@ -325,21 +351,19 @@ google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= -gorm.io/driver/sqlserver v1.6.0 h1:VZOBQVsVhkHU/NzNhRJKoANt5pZGQAS1Bwc6m6dgfnc= -gorm.io/driver/sqlserver v1.6.0/go.mod h1:WQzt4IJo/WHKnckU9jXBLMJIVNMVeTu25dnOzehntWw= +gorm.io/driver/sqlserver v1.6.1 h1:XWISFsu2I2pqd1KJhhTZNJMx1jNQ+zVL/Q8ovDcUjtY= +gorm.io/driver/sqlserver v1.6.1/go.mod h1:VZeNn7hqX1aXoN5TPAFGWvxWG90xtA8erGn2gQmpc6U= gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs= gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= modernc.org/cc/v4 v4.26.0 h1:QMYvbVduUGH0rrO+5mqF/PSPPRZNpRtg2CLELy7vUpA= From 6a8b28df881c689ebfa6f02dce28fb1bf6ff07d3 Mon Sep 17 00:00:00 2001 From: h44z Date: Sun, 27 Jul 2025 00:15:27 +0200 Subject: [PATCH 21/22] add dark mode (#482) (#489) --- frontend/index.html | 2 +- frontend/package-lock.json | 16 +++--- frontend/package.json | 4 +- frontend/src/App.vue | 60 ++++++++++++++++++++++- frontend/src/assets/base.css | 8 +++ frontend/src/components/PeerViewModal.vue | 4 +- frontend/src/views/AuditView.vue | 2 +- frontend/src/views/HomeView.vue | 8 +-- frontend/src/views/InterfaceView.vue | 6 ++- frontend/src/views/ProfileView.vue | 4 +- frontend/src/views/SettingsView.vue | 12 ++--- frontend/src/views/UserView.vue | 2 +- 12 files changed, 97 insertions(+), 31 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index fd8033f..287ef99 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1,5 +1,5 @@ - + diff --git a/frontend/package-lock.json b/frontend/package-lock.json index afbb37b..db118ca 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,8 +14,8 @@ "@popperjs/core": "^2.11.8", "@simplewebauthn/browser": "^13.1.0", "@vojtechlanka/vue-tags-input": "^3.1.1", - "bootstrap": "^5.3.5", - "bootswatch": "^5.3.5", + "bootstrap": "^5.3.7", + "bootswatch": "^5.3.7", "flag-icons": "^7.3.2", "ip-address": "^10.0.1", "is-cidr": "^5.1.1", @@ -1048,9 +1048,9 @@ } }, "node_modules/bootstrap": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.5.tgz", - "integrity": "sha512-ct1CHKtiobRimyGzmsSldEtM03E8fcEX4Tb3dGXz1V8faRwM50+vfHwTzOxB3IlKO7m+9vTH3s/3C6T2EAPeTA==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz", + "integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==", "funding": [ { "type": "github", @@ -1067,9 +1067,9 @@ } }, "node_modules/bootswatch": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-5.3.5.tgz", - "integrity": "sha512-1z8LNoUL5NHmv/hNROALQ6qtjw9OJIjMgP8ovBlIft+oI15b/mvnzxGL896iO9LtoDZH0Vdm+D2YW+j03GduSg==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-5.3.7.tgz", + "integrity": "sha512-n0X99+Jmpmd4vgkli5KwMOuAkgdyUPhq7cIAwoGXbM6WhE/mmkWACfxpr7WZeG9Pdx509Ndi+2K1HlzXXOr8/Q==", "license": "MIT" }, "node_modules/buffer-builder": { diff --git a/frontend/package.json b/frontend/package.json index 0be893a..e226a95 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,8 +14,8 @@ "@popperjs/core": "^2.11.8", "@simplewebauthn/browser": "^13.1.0", "@vojtechlanka/vue-tags-input": "^3.1.1", - "bootstrap": "^5.3.5", - "bootswatch": "^5.3.5", + "bootstrap": "^5.3.7", + "bootswatch": "^5.3.7", "flag-icons": "^7.3.2", "ip-address": "^10.0.1", "is-cidr": "^5.1.1", diff --git a/frontend/src/App.vue b/frontend/src/App.vue index e6e20d2..cddea54 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -14,6 +14,10 @@ const settings = settingsStore() onMounted(async () => { console.log("Starting WireGuard Portal frontend..."); + // restore theme from localStorage + const theme = localStorage.getItem('wgTheme') || 'light'; + document.documentElement.setAttribute('data-bs-theme', theme); + await sec.LoadSecurityProperties(); await auth.LoadProviders(); @@ -40,6 +44,13 @@ const switchLanguage = function (lang) { } } +const switchTheme = function (theme) { + if (document.documentElement.getAttribute('data-bs-theme') !== theme) { + localStorage.setItem('wgTheme', theme); + document.documentElement.setAttribute('data-bs-theme', theme); + } +} + const languageFlag = computed(() => { // `this` points to the component instance let lang = appGlobal.$i18n.locale.toLowerCase(); @@ -125,6 +136,24 @@ const userDisplayName = computed(() => { + @@ -141,7 +170,7 @@ const userDisplayName = computed(() => {
-
diff --git a/frontend/src/views/AuditView.vue b/frontend/src/views/AuditView.vue index 108827a..ccd78f7 100644 --- a/frontend/src/views/AuditView.vue +++ b/frontend/src/views/AuditView.vue @@ -26,7 +26,7 @@ onMounted(async () => {
- +
diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue index 0291ca7..be87e56 100644 --- a/frontend/src/views/HomeView.vue +++ b/frontend/src/views/HomeView.vue @@ -13,21 +13,21 @@ const auth = authStore()

{{ $t('home.abstract') }}

-
+

{{ $t('home.profiles.headline') }}

{{ $t('home.profiles.abstract') }}


-

{{ $t('home.profiles.content') }}

+

{{ $t('home.profiles.content') }}

{{ $t('home.profiles.button') }}

-
+

{{ $t('home.admin.headline') }}

{{ $t('home.admin.abstract') }}


-

{{ $t('home.admin.content') }}

+

{{ $t('home.admin.content') }}

{{ $t('home.admin.button-admin') }} diff --git a/frontend/src/views/InterfaceView.vue b/frontend/src/views/InterfaceView.vue index 1084081..1cdb9fb 100644 --- a/frontend/src/views/InterfaceView.vue +++ b/frontend/src/views/InterfaceView.vue @@ -112,7 +112,7 @@ onMounted(async () => {

- - +
@@ -429,3 +429,5 @@ onMounted(async () => {
+ diff --git a/frontend/src/views/ProfileView.vue b/frontend/src/views/ProfileView.vue index a5daec2..ea73fab 100644 --- a/frontend/src/views/ProfileView.vue +++ b/frontend/src/views/ProfileView.vue @@ -65,7 +65,7 @@ onMounted(async () => {
-
@@ -73,7 +73,7 @@ onMounted(async () => {
- - +
From 3f76aa416f6640db12f91b0059ca3388778d2e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wo=C5=BAniak?= Date: Sun, 27 Jul 2025 23:32:34 +0200 Subject: [PATCH 22/22] chore(logs): added more debug logs and reformated those files using gofmt (#490) --- internal/adapters/wireguard.go | 40 ++++++++++++++++++++++++---- internal/app/api/core/server.go | 1 + internal/app/wireguard/statistics.go | 1 + 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/internal/adapters/wireguard.go b/internal/adapters/wireguard.go index 6c15771..327d54a 100644 --- a/internal/adapters/wireguard.go +++ b/internal/adapters/wireguard.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "os" "github.com/vishvananda/netlink" @@ -16,8 +17,9 @@ import ( // WgRepo implements all low-level WireGuard interactions. type WgRepo struct { - wg lowlevel.WireGuardClient - nl lowlevel.NetlinkClient + wg lowlevel.WireGuardClient + nl lowlevel.NetlinkClient + log *slog.Logger } // NewWireGuardRepository creates a new WgRepo instance. @@ -31,8 +33,9 @@ func NewWireGuardRepository() *WgRepo { nl := &lowlevel.NetlinkManager{} repo := &WgRepo{ - wg: wg, - nl: nl, + wg: wg, + nl: nl, + log: slog.Default().With(slog.String("adapter", "wireguard")), } return repo @@ -40,8 +43,10 @@ func NewWireGuardRepository() *WgRepo { // GetInterfaces returns all existing WireGuard interfaces. func (r *WgRepo) GetInterfaces(_ context.Context) ([]domain.PhysicalInterface, error) { + r.log.Debug("getting all interfaces") devices, err := r.wg.Devices() if err != nil { + r.log.Error("failed to get devices", "error", err) return nil, fmt.Errorf("device list error: %w", err) } @@ -60,14 +65,17 @@ func (r *WgRepo) GetInterfaces(_ context.Context) ([]domain.PhysicalInterface, e // GetInterface returns the interface with the given id. // If no interface is found, an error os.ErrNotExist is returned. func (r *WgRepo) GetInterface(_ context.Context, id domain.InterfaceIdentifier) (*domain.PhysicalInterface, error) { + r.log.Debug("getting interface", "id", id) return r.getInterface(id) } // GetPeers returns all peers associated with the given interface id. // If the requested interface is found, an error os.ErrNotExist is returned. func (r *WgRepo) GetPeers(_ context.Context, deviceId domain.InterfaceIdentifier) ([]domain.PhysicalPeer, error) { + r.log.Debug("getting peers for interface", "deviceId", deviceId) device, err := r.wg.Device(string(deviceId)) if err != nil { + r.log.Error("failed to get device", "deviceId", deviceId, "error", err) return nil, fmt.Errorf("device error: %w", err) } @@ -90,6 +98,7 @@ func (r *WgRepo) GetPeer( deviceId domain.InterfaceIdentifier, id domain.PeerIdentifier, ) (*domain.PhysicalPeer, error) { + r.log.Debug("getting peer", "deviceId", deviceId, "peerId", id) return r.getPeer(deviceId, id) } @@ -174,25 +183,31 @@ func (r *WgRepo) SaveInterface( id domain.InterfaceIdentifier, updateFunc func(pi *domain.PhysicalInterface) (*domain.PhysicalInterface, error), ) error { + r.log.Debug("saving interface", "id", id) physicalInterface, err := r.getOrCreateInterface(id) if err != nil { + r.log.Error("failed to get or create interface", "id", id, "error", err) return err } if updateFunc != nil { physicalInterface, err = updateFunc(physicalInterface) if err != nil { + r.log.Error("interface update function failed", "id", id, "error", err) return err } } if err := r.updateLowLevelInterface(physicalInterface); err != nil { + r.log.Error("failed to update low level interface", "id", id, "error", err) return err } if err := r.updateWireGuardInterface(physicalInterface); err != nil { + r.log.Error("failed to update wireguard interface", "id", id, "error", err) return err } + r.log.Debug("successfully saved interface", "id", id) return nil } @@ -323,10 +338,13 @@ func (r *WgRepo) updateWireGuardInterface(pi *domain.PhysicalInterface) error { // DeleteInterface deletes the interface with the given id. // If the requested interface is found, no error is returned. func (r *WgRepo) DeleteInterface(_ context.Context, id domain.InterfaceIdentifier) error { + r.log.Debug("deleting interface", "id", id) if err := r.deleteLowLevelInterface(id); err != nil { + r.log.Error("failed to delete low level interface", "id", id, "error", err) return err } + r.log.Debug("successfully deleted interface", "id", id) return nil } @@ -356,20 +374,25 @@ func (r *WgRepo) SavePeer( id domain.PeerIdentifier, updateFunc func(pp *domain.PhysicalPeer) (*domain.PhysicalPeer, error), ) error { + r.log.Debug("saving peer", "deviceId", deviceId, "peerId", id) physicalPeer, err := r.getOrCreatePeer(deviceId, id) if err != nil { + r.log.Error("failed to get or create peer", "deviceId", deviceId, "peerId", id, "error", err) return err } physicalPeer, err = updateFunc(physicalPeer) if err != nil { + r.log.Error("peer update function failed", "deviceId", deviceId, "peerId", id, "error", err) return err } if err := r.updatePeer(deviceId, physicalPeer); err != nil { + r.log.Error("failed to update peer", "deviceId", deviceId, "peerId", id, "error", err) return err } + r.log.Debug("successfully saved peer", "deviceId", deviceId, "peerId", id) return nil } @@ -441,6 +464,7 @@ func (r *WgRepo) updatePeer(deviceId domain.InterfaceIdentifier, pp *domain.Phys err := r.wg.ConfigureDevice(string(deviceId), wgtypes.Config{ReplacePeers: false, Peers: []wgtypes.PeerConfig{cfg}}) if err != nil { + r.log.Error("failed to configure device for peer update", "deviceId", deviceId, "peerId", pp.Identifier, "error", err) return err } @@ -450,15 +474,20 @@ func (r *WgRepo) updatePeer(deviceId domain.InterfaceIdentifier, pp *domain.Phys // DeletePeer deletes the peer with the given id. // If the requested interface or peer is found, no error is returned. func (r *WgRepo) DeletePeer(_ context.Context, deviceId domain.InterfaceIdentifier, id domain.PeerIdentifier) error { + r.log.Debug("deleting peer", "deviceId", deviceId, "peerId", id) if !id.IsPublicKey() { - return errors.New("invalid public key") + err := errors.New("invalid public key") + r.log.Error("invalid peer id", "peerId", id, "error", err) + return err } err := r.deletePeer(deviceId, id) if err != nil { + r.log.Error("failed to delete peer", "deviceId", deviceId, "peerId", id, "error", err) return err } + r.log.Debug("successfully deleted peer", "deviceId", deviceId, "peerId", id) return nil } @@ -470,6 +499,7 @@ func (r *WgRepo) deletePeer(deviceId domain.InterfaceIdentifier, id domain.PeerI err := r.wg.ConfigureDevice(string(deviceId), wgtypes.Config{ReplacePeers: false, Peers: []wgtypes.PeerConfig{cfg}}) if err != nil { + r.log.Error("failed to configure device for peer deletion", "deviceId", deviceId, "peerId", id, "error", err) return err } diff --git a/internal/app/api/core/server.go b/internal/app/api/core/server.go index fe0d1e6..87b5519 100644 --- a/internal/app/api/core/server.go +++ b/internal/app/api/core/server.go @@ -100,6 +100,7 @@ func (s *Server) Run(ctx context.Context, listenAddress string) { srvContext, cancelFn := context.WithCancel(ctx) go func() { var err error + slog.Debug("starting server", "certFile", s.cfg.Web.CertFile, "keyFile", s.cfg.Web.KeyFile) if s.cfg.Web.CertFile != "" && s.cfg.Web.KeyFile != "" { err = srv.ListenAndServeTLS(s.cfg.Web.CertFile, s.cfg.Web.KeyFile) } else { diff --git a/internal/app/wireguard/statistics.go b/internal/app/wireguard/statistics.go index dcc8b36..9ab8946 100644 --- a/internal/app/wireguard/statistics.go +++ b/internal/app/wireguard/statistics.go @@ -197,6 +197,7 @@ func (c *StatisticsCollector) collectPeerData(ctx context.Context) { p.CalcConnected() if wasConnected != p.IsConnected { + slog.Debug("peer connection state changed", "peer", peer.Identifier, "connected", p.IsConnected) connectionStateChanged = true newPeerStatus = *p // store new status for event publishing }