playback-device-server/management/user_manager.go

192 lines
4.1 KiB
Go

package management
import (
"crypto/rand"
"encoding/base64"
"fmt"
d "playback-device-server/data"
"time"
"github.com/rs/zerolog/log"
)
const DEFAULT_USERNAME = "admin"
const MIN_PASSWORD_LENGTH = 6
type UserManager struct {
userDatabase *d.UserDatabase
}
func (um *UserManager) Initialize(userDatabase *d.UserDatabase) error {
um.userDatabase = userDatabase
exists, error := um.UsernameExists(DEFAULT_USERNAME)
if error != nil {
return error
}
if !exists {
password, error := generateRandomPassword(MIN_PASSWORD_LENGTH)
if error != nil {
return error
}
log.Info().Str("username", DEFAULT_USERNAME).Str("password", password).Msg("creating default admin user")
user := d.User{Username: DEFAULT_USERNAME, Password: password, IsAdmin: true}
_, error = um.CreateUser(&user)
if error != nil {
return error
}
}
return nil
}
func (um *UserManager) CreateUser(user *d.User) (string, error) {
exists, error := um.UsernameExists(user.Username)
if error != nil {
return "", error
}
if exists {
return "", fmt.Errorf("User '%s' already exists", user.Username)
}
if !isValidPassword(user.Password) {
return "", fmt.Errorf("invalid password")
}
id, error := um.userDatabase.CreateUser(user.Username, user.Password, user.IsAdmin)
if error != nil {
return "", error
}
return id, nil
}
func (um *UserManager) UsernameExists(username string) (bool, error) {
exists, error := um.userDatabase.UsernameExists(username)
if error != nil {
return false, error
}
return exists, nil
}
func (um *UserManager) UserIdExists(id string) (bool, error) {
exists, error := um.userDatabase.UserIdExists(id)
if error != nil {
return false, error
}
return exists, nil
}
func (um *UserManager) Login(username, password string) (string, error) {
exists, error := um.UsernameExists(username)
if error != nil {
return "", error
}
if !exists {
return "", fmt.Errorf("user '%s' doesn't exist", username)
}
correct, error := um.userDatabase.CheckCredentials(username, password)
if error != nil {
return "", error
}
if !correct {
return "", fmt.Errorf("wrong password")
}
user, error := um.userDatabase.GetUserByUsername(username)
if error != nil {
return "", error
}
expiryDate := time.Now().AddDate(0, 0, 30)
token, error := um.userDatabase.CreateSession(user.ID, expiryDate)
if error != nil {
return "", error
}
return token, nil
}
func (um *UserManager) GetSession(sessionToken string) (*d.UserSession, error) {
session, error := um.userDatabase.GetSession(sessionToken)
if error != nil {
return nil, error
}
return session, nil
}
func (um *UserManager) GetUserById(id string) (*d.User, error) {
user, error := um.userDatabase.GetUserById(id)
if error != nil {
return nil, error
}
return user, nil
}
func (um *UserManager) UpdateUser(user *d.User) error {
error := um.userDatabase.UpdateUser(user)
return error
}
func (um *UserManager) UpdatePassword(currentPassword string, newPassword string, user *d.User) error {
correct, error := um.userDatabase.CheckCredentials(user.Username, currentPassword)
if error != nil {
return error
}
if !correct {
return fmt.Errorf("wrong password")
}
if !isValidPassword(user.Password) {
return fmt.Errorf("invalid password")
}
error = um.userDatabase.UpdatePassword(user.ID, newPassword)
return error
}
func (um *UserManager) DeleteSession(token string) error {
error := um.userDatabase.DeleteSessionByToken(token)
if error != nil {
return error
}
return nil
}
func (um *UserManager) GetUsers() (*[]d.User, error) {
users, error := um.userDatabase.GetUsers()
return users, error
}
func (um *UserManager) DeleteUser(ID string) error {
error := um.userDatabase.DeleteUser(ID)
return error
}
func isValidPassword(password string) bool {
return len(password) >= MIN_PASSWORD_LENGTH
}
func generateRandomPassword(length int) (string, error) {
numBytes := length * 3 / 4 // Base64 encoding increases length by 4/3
randomBytes := make([]byte, numBytes)
_, err := rand.Read(randomBytes)
if err != nil {
return "", err
}
password := base64.URLEncoding.EncodeToString(randomBytes)
if len(password) > length {
password = password[:length]
}
return password, nil
}