2025-03-23 23:09:47 +01:00
|
|
|
package backend
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2025-10-15 21:11:40 +02:00
|
|
|
"fmt"
|
|
|
|
"strings"
|
2025-03-23 23:09:47 +01:00
|
|
|
|
|
|
|
"github.com/h44z/wg-portal/internal/config"
|
|
|
|
"github.com/h44z/wg-portal/internal/domain"
|
|
|
|
)
|
|
|
|
|
|
|
|
// region dependencies
|
|
|
|
|
|
|
|
type UserServiceUserManager interface {
|
|
|
|
GetUser(ctx context.Context, id domain.UserIdentifier) (*domain.User, error)
|
|
|
|
GetAllUsers(ctx context.Context) ([]domain.User, error)
|
|
|
|
CreateUser(ctx context.Context, user *domain.User) (*domain.User, error)
|
|
|
|
UpdateUser(ctx context.Context, user *domain.User) (*domain.User, error)
|
|
|
|
DeleteUser(ctx context.Context, id domain.UserIdentifier) error
|
|
|
|
ActivateApi(ctx context.Context, id domain.UserIdentifier) (*domain.User, error)
|
|
|
|
DeactivateApi(ctx context.Context, id domain.UserIdentifier) (*domain.User, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
type UserServiceWireGuardManager interface {
|
|
|
|
GetUserPeers(ctx context.Context, id domain.UserIdentifier) ([]domain.Peer, error)
|
|
|
|
GetUserInterfaces(ctx context.Context, _ domain.UserIdentifier) ([]domain.Interface, error)
|
|
|
|
GetUserPeerStats(ctx context.Context, id domain.UserIdentifier) ([]domain.PeerStatus, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// endregion dependencies
|
|
|
|
|
|
|
|
type UserService struct {
|
|
|
|
cfg *config.Config
|
|
|
|
|
|
|
|
users UserServiceUserManager
|
|
|
|
wg UserServiceWireGuardManager
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewUserService(cfg *config.Config, users UserServiceUserManager, wg UserServiceWireGuardManager) *UserService {
|
|
|
|
return &UserService{
|
|
|
|
cfg: cfg,
|
|
|
|
users: users,
|
|
|
|
wg: wg,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u UserService) GetUser(ctx context.Context, id domain.UserIdentifier) (*domain.User, error) {
|
|
|
|
return u.users.GetUser(ctx, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u UserService) GetAllUsers(ctx context.Context) ([]domain.User, error) {
|
|
|
|
return u.users.GetAllUsers(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u UserService) UpdateUser(ctx context.Context, user *domain.User) (*domain.User, error) {
|
|
|
|
return u.users.UpdateUser(ctx, user)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u UserService) CreateUser(ctx context.Context, user *domain.User) (*domain.User, error) {
|
|
|
|
return u.users.CreateUser(ctx, user)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u UserService) DeleteUser(ctx context.Context, id domain.UserIdentifier) error {
|
|
|
|
return u.users.DeleteUser(ctx, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u UserService) ActivateApi(ctx context.Context, id domain.UserIdentifier) (*domain.User, error) {
|
|
|
|
return u.users.ActivateApi(ctx, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u UserService) DeactivateApi(ctx context.Context, id domain.UserIdentifier) (*domain.User, error) {
|
|
|
|
return u.users.DeactivateApi(ctx, id)
|
|
|
|
}
|
|
|
|
|
2025-10-15 21:11:40 +02:00
|
|
|
func (u UserService) ChangePassword(ctx context.Context, id domain.UserIdentifier, oldPassword, newPassword string) (*domain.User, error) {
|
|
|
|
oldPassword = strings.TrimSpace(oldPassword)
|
|
|
|
newPassword = strings.TrimSpace(newPassword)
|
|
|
|
|
|
|
|
if newPassword == "" {
|
|
|
|
return nil, fmt.Errorf("new password must not be empty")
|
|
|
|
}
|
|
|
|
|
|
|
|
// ensure that the new password is different from the old one
|
|
|
|
if oldPassword == newPassword {
|
|
|
|
return nil, fmt.Errorf("new password must be different from the old one")
|
|
|
|
}
|
|
|
|
|
|
|
|
user, err := u.users.GetUser(ctx, id)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to get user: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ensure that the user uses the database backend; otherwise we can't change the password
|
|
|
|
if user.Source != domain.UserSourceDatabase {
|
|
|
|
return nil, fmt.Errorf("user source %s does not support password changes", user.Source)
|
|
|
|
}
|
|
|
|
|
|
|
|
// validate old password
|
|
|
|
if user.CheckPassword(oldPassword) != nil {
|
|
|
|
return nil, fmt.Errorf("current password is invalid")
|
|
|
|
}
|
|
|
|
|
|
|
|
user.Password = domain.PrivateString(newPassword)
|
|
|
|
|
|
|
|
// ensure that the new password is strong enough
|
|
|
|
if err := user.HasWeakPassword(u.cfg.Auth.MinPasswordLength); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return u.users.UpdateUser(ctx, user)
|
|
|
|
}
|
|
|
|
|
2025-03-23 23:09:47 +01:00
|
|
|
func (u UserService) GetUserPeers(ctx context.Context, id domain.UserIdentifier) ([]domain.Peer, error) {
|
|
|
|
return u.wg.GetUserPeers(ctx, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u UserService) GetUserPeerStats(ctx context.Context, id domain.UserIdentifier) ([]domain.PeerStatus, error) {
|
|
|
|
return u.wg.GetUserPeerStats(ctx, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u UserService) GetUserInterfaces(ctx context.Context, id domain.UserIdentifier) ([]domain.Interface, error) {
|
|
|
|
return u.wg.GetUserInterfaces(ctx, id)
|
|
|
|
}
|