mirror of
https://github.com/datarhei/core.git
synced 2025-10-05 16:07:07 +08:00
262 lines
5.8 KiB
Go
262 lines
5.8 KiB
Go
package identity
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/datarhei/core/v16/slices"
|
|
)
|
|
|
|
type User struct {
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
Name string `json:"name"`
|
|
Alias string `json:"alias"`
|
|
Superuser bool `json:"superuser"`
|
|
Auth UserAuth `json:"auth"`
|
|
}
|
|
|
|
type UserAuth struct {
|
|
API UserAuthAPI `json:"api"`
|
|
Services UserAuthServices `json:"services"`
|
|
}
|
|
|
|
type UserAuthAPI struct {
|
|
Password string `json:"password"`
|
|
Auth0 UserAuthAPIAuth0 `json:"auth0"`
|
|
}
|
|
|
|
type UserAuthAPIAuth0 struct {
|
|
User string `json:"user"`
|
|
Tenant Auth0Tenant `json:"tenant"`
|
|
}
|
|
|
|
type UserAuthServices struct {
|
|
Basic []string `json:"basic"` // Passwords for BasicAuth
|
|
Token []string `json:"token"` // Tokens/Streamkey for RTMP and SRT
|
|
Session []string `json:"session"` // Secrets for session JWT
|
|
}
|
|
|
|
func (u *User) Validate() error {
|
|
if len(u.Name) == 0 {
|
|
return fmt.Errorf("a name is required")
|
|
}
|
|
|
|
if strings.HasPrefix(u.Name, "$") {
|
|
return fmt.Errorf("name is not allowed to start with $")
|
|
}
|
|
|
|
if len(u.Alias) != 0 {
|
|
if strings.HasPrefix(u.Alias, "$") {
|
|
return fmt.Errorf("alias is not allowed to start with $")
|
|
}
|
|
}
|
|
|
|
if len(u.Auth.API.Auth0.User) != 0 {
|
|
t, err := newAuth0Tenant(u.Auth.API.Auth0.Tenant)
|
|
if err != nil {
|
|
return fmt.Errorf("auth0: %w", err)
|
|
}
|
|
|
|
t.Cancel()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (u *User) marshalIdentity() *identity {
|
|
i := &identity{
|
|
user: u.clone(),
|
|
}
|
|
|
|
return i
|
|
}
|
|
|
|
func (u *User) clone() User {
|
|
user := *u
|
|
|
|
user.Auth.Services.Basic = slices.Copy(u.Auth.Services.Basic)
|
|
user.Auth.Services.Token = slices.Copy(u.Auth.Services.Token)
|
|
user.Auth.Services.Session = slices.Copy(u.Auth.Services.Session)
|
|
|
|
return user
|
|
}
|
|
|
|
type UserList interface {
|
|
Add(u User) error
|
|
Get(nameOrAlias string) (User, error)
|
|
Update(nameOrAlias string, u User) error
|
|
Delete(nameorAlias string)
|
|
List() []User
|
|
}
|
|
|
|
type userlist struct {
|
|
namesUserMap map[string]string
|
|
auth0UserMap map[string]string
|
|
user map[string]User
|
|
}
|
|
|
|
func NewUserList() UserList {
|
|
return &userlist{
|
|
namesUserMap: map[string]string{},
|
|
auth0UserMap: map[string]string{},
|
|
user: map[string]User{},
|
|
}
|
|
}
|
|
|
|
// Add implements UserList.
|
|
func (ul *userlist) Add(u User) error {
|
|
if err := u.Validate(); err != nil {
|
|
return fmt.Errorf("invalid user: %w", err)
|
|
}
|
|
|
|
if _, ok := ul.namesUserMap[u.Name]; ok {
|
|
return fmt.Errorf("the name '%s' is already in use", u.Name)
|
|
}
|
|
|
|
if len(u.Alias) != 0 {
|
|
if _, ok := ul.namesUserMap[u.Alias]; ok {
|
|
return fmt.Errorf("the alias '%s' is already in use", u.Alias)
|
|
}
|
|
}
|
|
|
|
if len(u.Auth.API.Auth0.User) != 0 {
|
|
if name, ok := ul.auth0UserMap[u.Auth.API.Auth0.User]; ok {
|
|
return fmt.Errorf("the Auth0 user has already an identity (%s)", name)
|
|
}
|
|
}
|
|
|
|
u = u.clone()
|
|
|
|
ul.namesUserMap[u.Name] = u.Name
|
|
if len(u.Alias) != 0 {
|
|
ul.namesUserMap[u.Alias] = u.Name
|
|
}
|
|
if len(u.Auth.API.Auth0.User) != 0 {
|
|
ul.auth0UserMap[u.Auth.API.Auth0.User] = u.Name
|
|
}
|
|
|
|
ul.user[u.Name] = u
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ul *userlist) Get(nameOrAlias string) (User, error) {
|
|
name, ok := ul.namesUserMap[nameOrAlias]
|
|
if !ok {
|
|
return User{}, fmt.Errorf("user not found")
|
|
}
|
|
|
|
u, ok := ul.user[name]
|
|
if !ok {
|
|
return User{}, fmt.Errorf("user not found")
|
|
}
|
|
|
|
return u.clone(), nil
|
|
}
|
|
|
|
// Delete implements UserList.
|
|
func (ul *userlist) Delete(nameOrAlias string) {
|
|
name, ok := ul.namesUserMap[nameOrAlias]
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
u, ok := ul.user[name]
|
|
if !ok {
|
|
delete(ul.namesUserMap, nameOrAlias)
|
|
return
|
|
}
|
|
|
|
delete(ul.namesUserMap, u.Name)
|
|
delete(ul.namesUserMap, u.Alias)
|
|
delete(ul.auth0UserMap, u.Auth.API.Auth0.User)
|
|
delete(ul.user, u.Name)
|
|
}
|
|
|
|
// List implements UserList.
|
|
func (ul *userlist) List() []User {
|
|
user := []User{}
|
|
|
|
for _, u := range ul.user {
|
|
user = append(user, u.clone())
|
|
}
|
|
|
|
return user
|
|
}
|
|
|
|
// Update implements UserList.
|
|
func (ul *userlist) Update(nameOrAlias string, u User) error {
|
|
if err := u.Validate(); err != nil {
|
|
return fmt.Errorf("invalid user: %w", err)
|
|
}
|
|
|
|
name, ok := ul.namesUserMap[nameOrAlias]
|
|
if !ok {
|
|
return fmt.Errorf("user with the name or alias '%s' not found", nameOrAlias)
|
|
}
|
|
|
|
oldUser, ok := ul.user[name]
|
|
if !ok {
|
|
return fmt.Errorf("user with the name '%s' not found", name)
|
|
}
|
|
|
|
delete(ul.namesUserMap, oldUser.Name)
|
|
delete(ul.namesUserMap, oldUser.Alias)
|
|
delete(ul.auth0UserMap, oldUser.Auth.API.Auth0.User)
|
|
|
|
if _, ok := ul.namesUserMap[u.Name]; ok {
|
|
ul.namesUserMap[oldUser.Name] = oldUser.Name
|
|
if len(oldUser.Alias) != 0 {
|
|
ul.namesUserMap[oldUser.Alias] = oldUser.Name
|
|
}
|
|
if len(oldUser.Auth.API.Auth0.User) != 0 {
|
|
ul.auth0UserMap[oldUser.Auth.API.Auth0.User] = oldUser.Name
|
|
}
|
|
return fmt.Errorf("the name '%s' is already in use", u.Name)
|
|
}
|
|
|
|
if len(u.Alias) != 0 {
|
|
if _, ok := ul.namesUserMap[u.Alias]; ok {
|
|
ul.namesUserMap[oldUser.Name] = oldUser.Name
|
|
if len(oldUser.Alias) != 0 {
|
|
ul.namesUserMap[oldUser.Alias] = oldUser.Name
|
|
}
|
|
if len(oldUser.Auth.API.Auth0.User) != 0 {
|
|
ul.auth0UserMap[oldUser.Auth.API.Auth0.User] = oldUser.Name
|
|
}
|
|
return fmt.Errorf("the alias '%s' is already in use", u.Alias)
|
|
}
|
|
}
|
|
|
|
if len(u.Auth.API.Auth0.User) != 0 {
|
|
if _, ok := ul.auth0UserMap[u.Auth.API.Auth0.User]; ok {
|
|
ul.namesUserMap[oldUser.Name] = oldUser.Name
|
|
if len(oldUser.Alias) != 0 {
|
|
ul.namesUserMap[oldUser.Alias] = oldUser.Name
|
|
}
|
|
if len(oldUser.Auth.API.Auth0.User) != 0 {
|
|
ul.auth0UserMap[oldUser.Auth.API.Auth0.User] = oldUser.Name
|
|
}
|
|
return fmt.Errorf("the Auth0 user has already an identity (%s)", u.Auth.API.Auth0.User)
|
|
}
|
|
}
|
|
|
|
delete(ul.user, oldUser.Name)
|
|
|
|
u = u.clone()
|
|
|
|
ul.namesUserMap[u.Name] = u.Name
|
|
if len(u.Alias) != 0 {
|
|
ul.namesUserMap[u.Alias] = u.Name
|
|
}
|
|
if len(u.Auth.API.Auth0.User) != 0 {
|
|
ul.auth0UserMap[u.Auth.API.Auth0.User] = u.Name
|
|
}
|
|
|
|
ul.user[u.Name] = u
|
|
|
|
return nil
|
|
}
|