mirror of
https://github.com/h44z/wg-portal.git
synced 2026-02-25 11:56:23 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a8ec71b3f | ||
|
|
fe4485037a |
@@ -16,7 +16,7 @@ annotations:
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.7.2
|
||||
version: 0.7.3
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# wg-portal
|
||||
|
||||
  
|
||||
  
|
||||
|
||||
WireGuard Configuration Portal with LDAP, OAuth, OIDC authentication
|
||||
|
||||
@@ -41,6 +41,7 @@ The [Values](#values) section lists the parameters that can be configured during
|
||||
| config.web | tpl/object | `{}` | [Web configuration](https://wgportal.org/latest/documentation/configuration/overview/#web) options.<br> `listening_address` will be set automatically from `service.web.port`. `external_url` is required to enable ingress and certificate resources. |
|
||||
| revisionHistoryLimit | string | `10` | The number of old ReplicaSets to retain to allow rollback. |
|
||||
| workloadType | string | `"Deployment"` | Workload type - `Deployment` or `StatefulSet` |
|
||||
| replicas | int | `1` | The replicas for the workload. |
|
||||
| strategy | object | `{"type":"RollingUpdate"}` | Update strategy for the workload Valid values are: `RollingUpdate` or `Recreate` for Deployment, `RollingUpdate` or `OnDelete` for StatefulSet |
|
||||
| image.repository | string | `"ghcr.io/h44z/wg-portal"` | Image repository |
|
||||
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
|
||||
@@ -74,12 +75,15 @@ The [Values](#values) section lists the parameters that can be configured during
|
||||
| service.web.type | string | `"ClusterIP"` | Web service type |
|
||||
| service.web.port | int | `8888` | Web service port Used for the web interface listener |
|
||||
| service.web.appProtocol | string | `"http"` | Web service appProtocol. Will be auto set to `https` if certificate is enabled. |
|
||||
| service.web.extraSelectorLabels | object | `{}` | Extra labels to append to the selector labels. |
|
||||
| service.wireguard.annotations | object | `{}` | Annotations for the WireGuard service |
|
||||
| service.wireguard.type | string | `"LoadBalancer"` | Wireguard service type |
|
||||
| service.wireguard.ports | list | `[51820]` | Wireguard service ports. Exposes the WireGuard ports for created interfaces. Lowerest port is selected as start port for the first interface. Increment next port by 1 for each additional interface. |
|
||||
| service.wireguard.extraSelectorLabels | object | `{}` | Extra labels to append to the selector labels. |
|
||||
| service.metrics.port | int | `8787` | |
|
||||
| ingress.enabled | bool | `false` | Specifies whether an ingress resource should be created |
|
||||
| ingress.className | string | `""` | Ingress class name |
|
||||
| ingress.pathType | string | `"ImplementationSpecific"` | Ingress pathType value. Valid values are `ImplementationSpecific`, `Exact` or `Prefix`. |
|
||||
| ingress.annotations | object | `{}` | Ingress annotations |
|
||||
| ingress.tls | bool | `false` | Ingress TLS configuration. Enable certificate resource or add ingress annotation to create required secret |
|
||||
| certificate.enabled | bool | `false` | Specifies whether a certificate resource should be created. If enabled, certificate will be used for the web. |
|
||||
|
||||
@@ -49,7 +49,7 @@ spec:
|
||||
{{- with .scope.type }}
|
||||
type: {{ . }}
|
||||
{{- end }}
|
||||
selector: {{- include "wg-portal.selectorLabels" .context | nindent 4 }}
|
||||
selector: {{- include "wg-portal.util.merge" (list .context .scope.extraSelectorLabels "wg-portal.selectorLabels") | nindent 4 }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
|
||||
@@ -8,6 +8,9 @@ spec:
|
||||
{{- with .Values.revisionHistoryLimit }}
|
||||
revisionHistoryLimit: {{ . }}
|
||||
{{- end }}
|
||||
{{- with .Values.replicas }}
|
||||
replicas: {{ . }}
|
||||
{{- end }}
|
||||
{{- with .Values.strategy }}
|
||||
strategy: {{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -15,7 +15,7 @@ spec:
|
||||
http:
|
||||
paths:
|
||||
- path: {{ default "/" (urlParse (tpl .Values.config.web.external_url .)).path }}
|
||||
pathType: {{ default "ImplementationSpecific" .pathType }}
|
||||
pathType: {{ default "ImplementationSpecific" .Values.ingress.pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "wg-portal.fullname" . }}
|
||||
|
||||
@@ -8,6 +8,9 @@ spec:
|
||||
{{- with .Values.revisionHistoryLimit }}
|
||||
revisionHistoryLimit: {{ . }}
|
||||
{{- end }}
|
||||
{{- with .Values.replicas }}
|
||||
replicas: {{ . }}
|
||||
{{- end }}
|
||||
{{- with .Values.strategy }}
|
||||
updateStrategy: {{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -35,6 +35,9 @@ config:
|
||||
revisionHistoryLimit: ""
|
||||
# -- Workload type - `Deployment` or `StatefulSet`
|
||||
workloadType: Deployment
|
||||
# -- The replicas for the workload.
|
||||
# @default -- `1`
|
||||
replicas: 1
|
||||
# -- Update strategy for the workload
|
||||
# Valid values are:
|
||||
# `RollingUpdate` or `Recreate` for Deployment,
|
||||
@@ -124,6 +127,8 @@ service:
|
||||
port: 8888
|
||||
# -- Web service appProtocol. Will be auto set to `https` if certificate is enabled.
|
||||
appProtocol: http
|
||||
# -- Extra labels to append to the selector labels.
|
||||
extraSelectorLabels: {}
|
||||
wireguard:
|
||||
# -- Annotations for the WireGuard service
|
||||
annotations: {}
|
||||
@@ -135,6 +140,8 @@ service:
|
||||
# Increment next port by 1 for each additional interface.
|
||||
ports:
|
||||
- 51820
|
||||
# -- Extra labels to append to the selector labels.
|
||||
extraSelectorLabels: {}
|
||||
metrics:
|
||||
port: 8787
|
||||
|
||||
@@ -143,6 +150,10 @@ ingress:
|
||||
enabled: false
|
||||
# -- Ingress class name
|
||||
className: ""
|
||||
# -- Ingress pathType value.
|
||||
# Valid values are `ImplementationSpecific`, `Exact` or `Prefix`.
|
||||
# @default -- `"ImplementationSpecific"`
|
||||
pathType: "ImplementationSpecific"
|
||||
# -- Ingress annotations
|
||||
annotations: {}
|
||||
# -- Ingress TLS configuration.
|
||||
|
||||
@@ -53,6 +53,17 @@ func (u UserService) GetAllUsers(ctx context.Context) ([]domain.User, error) {
|
||||
}
|
||||
|
||||
func (u UserService) UpdateUser(ctx context.Context, user *domain.User) (*domain.User, error) {
|
||||
sessionUser := domain.GetUserInfo(ctx)
|
||||
currentUser, err := u.users.GetUser(ctx, user.Identifier)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if this endpoint is used by non-admins, make sure that the user can only modify a specific subset of attributes
|
||||
if !sessionUser.IsAdmin {
|
||||
user.CopyAdminAttributes(currentUser, u.cfg.Advanced.ApiAdminOnly)
|
||||
}
|
||||
|
||||
return u.users.UpdateUser(ctx, user)
|
||||
}
|
||||
|
||||
|
||||
@@ -352,8 +352,9 @@ func (m Manager) DeactivateApi(ctx context.Context, id domain.UserIdentifier) (*
|
||||
func (m Manager) validateModifications(ctx context.Context, old, new *domain.User) error {
|
||||
currentUser := domain.GetUserInfo(ctx)
|
||||
|
||||
if currentUser.Id != new.Identifier && !currentUser.IsAdmin {
|
||||
return fmt.Errorf("insufficient permissions")
|
||||
adminErrors := m.validateAdminModifications(ctx, old, new)
|
||||
if adminErrors != nil {
|
||||
return adminErrors
|
||||
}
|
||||
|
||||
if err := old.EditAllowed(new); err != nil && currentUser.Id != domain.SystemAdminContextUserInfo().Id {
|
||||
@@ -387,6 +388,42 @@ func (m Manager) validateModifications(ctx context.Context, old, new *domain.Use
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Manager) validateAdminModifications(ctx context.Context, old, new *domain.User) error {
|
||||
currentUser := domain.GetUserInfo(ctx)
|
||||
|
||||
if currentUser.IsAdmin {
|
||||
if currentUser.Id == old.Identifier && !new.IsAdmin {
|
||||
return fmt.Errorf("cannot remove own admin rights: %w", domain.ErrInvalidData)
|
||||
}
|
||||
|
||||
return nil // admins can do (almost) everything
|
||||
}
|
||||
|
||||
// non-admins can only modify very their own profile data
|
||||
|
||||
if currentUser.Id != new.Identifier {
|
||||
return fmt.Errorf("insufficient permissions: %w", domain.ErrInvalidData)
|
||||
}
|
||||
|
||||
if new.IsAdmin {
|
||||
return fmt.Errorf("cannot grant admin rights: %w", domain.ErrInvalidData)
|
||||
}
|
||||
|
||||
if new.Notes != old.Notes {
|
||||
return fmt.Errorf("cannot update notes: %w", domain.ErrInvalidData)
|
||||
}
|
||||
|
||||
if old.Locked != new.Locked || old.LockedReason != new.LockedReason {
|
||||
return fmt.Errorf("cannot change lock state: %w", domain.ErrInvalidData)
|
||||
}
|
||||
|
||||
if old.Disabled != new.Disabled || old.DisabledReason != new.DisabledReason {
|
||||
return fmt.Errorf("cannot change disabled state: %w", domain.ErrInvalidData)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Manager) validateCreation(ctx context.Context, new *domain.User) error {
|
||||
currentUser := domain.GetUserInfo(ctx)
|
||||
|
||||
@@ -453,6 +490,10 @@ func (m Manager) validateDeletion(ctx context.Context, del *domain.User) error {
|
||||
func (m Manager) validateApiChange(ctx context.Context, user *domain.User) error {
|
||||
currentUser := domain.GetUserInfo(ctx)
|
||||
|
||||
if !currentUser.IsAdmin && m.cfg.Advanced.ApiAdminOnly {
|
||||
return fmt.Errorf("insufficient permissions to change API access: %w", domain.ErrNoPermission)
|
||||
}
|
||||
|
||||
if currentUser.Id != user.Identifier {
|
||||
return fmt.Errorf("cannot change API access of user: %w", domain.ErrNoPermission)
|
||||
}
|
||||
|
||||
@@ -185,6 +185,31 @@ func (u *User) CopyCalculatedAttributes(src *User) {
|
||||
u.LinkedPeerCount = src.LinkedPeerCount
|
||||
}
|
||||
|
||||
// CopyAdminAttributes copies all attributes from the given user except password, passkey and
|
||||
// api-token if apiAdminOnly is false.
|
||||
func (u *User) CopyAdminAttributes(src *User, apiAdminOnly bool) {
|
||||
u.BaseModel = src.BaseModel
|
||||
u.Identifier = src.Identifier
|
||||
u.Email = src.Email
|
||||
u.Source = src.Source
|
||||
u.ProviderName = src.ProviderName
|
||||
u.IsAdmin = src.IsAdmin
|
||||
u.Firstname = src.Firstname
|
||||
u.Lastname = src.Lastname
|
||||
u.Phone = src.Phone
|
||||
u.Department = src.Department
|
||||
u.Notes = src.Notes
|
||||
u.Disabled = src.Disabled
|
||||
u.DisabledReason = src.DisabledReason
|
||||
u.Locked = src.Locked
|
||||
u.LockedReason = src.LockedReason
|
||||
u.LinkedPeerCount = src.LinkedPeerCount
|
||||
if apiAdminOnly {
|
||||
u.ApiToken = src.ApiToken
|
||||
u.ApiTokenCreated = src.ApiTokenCreated
|
||||
}
|
||||
}
|
||||
|
||||
// DisplayName returns the display name of the user.
|
||||
// The display name is the first and last name, or the email address of the user.
|
||||
// If none of these fields are set, the user identifier is returned.
|
||||
|
||||
Reference in New Issue
Block a user