allow multiple users to be set in object provider.

This commit is contained in:
Miroslav Šedivý 2023-01-13 00:39:30 +01:00
parent 107eba22a5
commit 1fb5ae43dd
5 changed files with 77 additions and 66 deletions

View File

@ -65,11 +65,41 @@ desktop:
member:
provider: "object"
object:
admin_password: "admin"
user_password: "neko"
users:
- username: "admin"
password: "admin"
profile:
name: "Administrator"
is_admin: true
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: true
- username: "user"
password: "neko"
profile:
name: "User"
is_admin: false
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: false
# provider: "file"
# file:
# path: "/home/neko/members.json"
# provider: "multiuser"
# multiuser:
# admin_password: "admin"
# user_password: "neko"
# provider: "noauth"
session:
# Allows reconnecting the websocket even if the previous

View File

@ -1,12 +1,14 @@
package config
import (
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/demodesk/neko/internal/member/file"
"github.com/demodesk/neko/internal/member/multiuser"
"github.com/demodesk/neko/internal/member/object"
"github.com/demodesk/neko/pkg/utils"
)
type Member struct {
@ -31,13 +33,8 @@ func (Member) Init(cmd *cobra.Command) error {
}
// object provider
cmd.PersistentFlags().String("member.object.user_password", "", "member object provider: user password")
if err := viper.BindPFlag("member.object.user_password", cmd.PersistentFlags().Lookup("member.object.user_password")); err != nil {
return err
}
cmd.PersistentFlags().String("member.object.admin_password", "", "member object provider: admin password")
if err := viper.BindPFlag("member.object.admin_password", cmd.PersistentFlags().Lookup("member.object.admin_password")); err != nil {
cmd.PersistentFlags().String("member.object.users", "[]", "member object provider: users in JSON format")
if err := viper.BindPFlag("member.object.users", cmd.PersistentFlags().Lookup("member.object.users")); err != nil {
return err
}
@ -62,8 +59,11 @@ func (s *Member) Set() {
s.File.Path = viper.GetString("member.file.path")
// object provider
s.Object.UserPassword = viper.GetString("member.object.user_password")
s.Object.AdminPassword = viper.GetString("member.object.admin_password")
if err := viper.UnmarshalKey("member.object.users", &s.Object.Users, viper.DecodeHook(
utils.JsonStringAutoDecode(s.Object.Users),
)); err != nil {
log.Warn().Err(err).Msgf("unable to parse member object users")
}
// multiuser provider
s.Multiuser.UserPassword = viper.GetString("member.multiuser.user_password")

View File

@ -7,48 +7,20 @@ import (
func New(config Config) types.MemberProvider {
return &MemberProviderCtx{
config: config,
entries: make(map[string]*MemberEntry),
entries: make(map[string]*memberEntry),
}
}
type MemberProviderCtx struct {
config Config
entries map[string]*MemberEntry
entries map[string]*memberEntry
}
func (provider *MemberProviderCtx) Connect() error {
var err error
if provider.config.AdminPassword != "" {
// create default admin account at startup
_, err = provider.Insert("admin", provider.config.AdminPassword, types.MemberProfile{
Name: "Administrator",
IsAdmin: true,
CanLogin: true,
CanConnect: true,
CanWatch: true,
CanHost: true,
CanShareMedia: true,
CanAccessClipboard: true,
SendsInactiveCursor: true,
CanSeeInactiveCursors: true,
})
}
if provider.config.UserPassword != "" {
// create default user account at startup
_, err = provider.Insert("user", provider.config.UserPassword, types.MemberProfile{
Name: "User",
IsAdmin: false,
CanLogin: true,
CanConnect: true,
CanWatch: true,
CanHost: true,
CanShareMedia: true,
CanAccessClipboard: true,
SendsInactiveCursor: true,
CanSeeInactiveCursors: false,
})
for _, entry := range provider.config.Users {
_, err = provider.Insert(entry.Username, entry.Password, entry.Profile)
}
return err
@ -68,11 +40,11 @@ func (provider *MemberProviderCtx) Authenticate(username string, password string
}
// TODO: Use hash function.
if entry.Password != password {
if !entry.CheckPassword(password) {
return "", types.MemberProfile{}, types.ErrMemberInvalidPassword
}
return id, entry.Profile, nil
return id, entry.profile, nil
}
func (provider *MemberProviderCtx) Insert(username string, password string, profile types.MemberProfile) (string, error) {
@ -84,10 +56,10 @@ func (provider *MemberProviderCtx) Insert(username string, password string, prof
return "", types.ErrMemberAlreadyExists
}
provider.entries[id] = &MemberEntry{
provider.entries[id] = &memberEntry{
// TODO: Use hash function.
Password: password,
Profile: profile,
password: password,
profile: profile,
}
return id, nil
@ -99,7 +71,7 @@ func (provider *MemberProviderCtx) UpdateProfile(id string, profile types.Member
return types.ErrMemberDoesNotExist
}
entry.Profile = profile
entry.profile = profile
return nil
}
@ -111,7 +83,7 @@ func (provider *MemberProviderCtx) UpdatePassword(id string, password string) er
}
// TODO: Use hash function.
entry.Password = password
entry.password = password
return nil
}
@ -122,7 +94,7 @@ func (provider *MemberProviderCtx) Select(id string) (types.MemberProfile, error
return types.MemberProfile{}, types.ErrMemberDoesNotExist
}
return entry.Profile, nil
return entry.profile, nil
}
func (provider *MemberProviderCtx) SelectAll(limit int, offset int) (map[string]types.MemberProfile, error) {
@ -131,7 +103,7 @@ func (provider *MemberProviderCtx) SelectAll(limit int, offset int) (map[string]
i := 0
for id, entry := range provider.entries {
if i >= offset && (limit == 0 || i < offset+limit) {
profiles[id] = entry.Profile
profiles[id] = entry.profile
}
i = i + 1

View File

@ -4,12 +4,21 @@ import (
"github.com/demodesk/neko/pkg/types"
)
type MemberEntry struct {
Password string `json:"password"`
Profile types.MemberProfile `json:"profile"`
type memberEntry struct {
password string
profile types.MemberProfile
}
func (m *memberEntry) CheckPassword(password string) bool {
return m.password == password
}
type User struct {
Username string
Password string
Profile types.MemberProfile
}
type Config struct {
AdminPassword string
UserPassword string
Users []User
}

View File

@ -12,15 +12,15 @@ type MemberProfile struct {
Name string `json:"name"`
// permissions
IsAdmin bool `json:"is_admin"`
CanLogin bool `json:"can_login"`
CanConnect bool `json:"can_connect"`
CanWatch bool `json:"can_watch"`
CanHost bool `json:"can_host"`
CanShareMedia bool `json:"can_share_media"`
CanAccessClipboard bool `json:"can_access_clipboard"`
SendsInactiveCursor bool `json:"sends_inactive_cursor"`
CanSeeInactiveCursors bool `json:"can_see_inactive_cursors"`
IsAdmin bool `json:"is_admin" mapstructure:"is_admin"`
CanLogin bool `json:"can_login" mapstructure:"can_login"`
CanConnect bool `json:"can_connect" mapstructure:"can_connect"`
CanWatch bool `json:"can_watch" mapstructure:"can_watch"`
CanHost bool `json:"can_host" mapstructure:"can_host"`
CanShareMedia bool `json:"can_share_media" mapstructure:"can_share_media"`
CanAccessClipboard bool `json:"can_access_clipboard" mapstructure:"can_access_clipboard"`
SendsInactiveCursor bool `json:"sends_inactive_cursor" mapstructure:"sends_inactive_cursor"`
CanSeeInactiveCursors bool `json:"can_see_inactive_cursors" mapstructure:"can_see_inactive_cursors"`
// plugin scope
Plugins map[string]any `json:"plugins"`