diff --git a/internal/config/member.go b/internal/config/member.go index 8ef083d5..2afeb7ae 100644 --- a/internal/config/member.go +++ b/internal/config/member.go @@ -5,6 +5,7 @@ import ( "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" ) @@ -12,8 +13,9 @@ type Member struct { Provider string // providers - File file.Config - Object object.Config + File file.Config + Object object.Config + Multiuser multiuser.Config } func (Member) Init(cmd *cobra.Command) error { @@ -39,6 +41,17 @@ func (Member) Init(cmd *cobra.Command) error { return err } + // multiuser provider + cmd.PersistentFlags().String("member.multiuser.user_password", "", "member multiuser provider: user password") + if err := viper.BindPFlag("member.multiuser.user_password", cmd.PersistentFlags().Lookup("member.multiuser.user_password")); err != nil { + return err + } + + cmd.PersistentFlags().String("member.multiuser.admin_password", "", "member multiuser provider: admin password") + if err := viper.BindPFlag("member.multiuser.admin_password", cmd.PersistentFlags().Lookup("member.multiuser.admin_password")); err != nil { + return err + } + return nil } @@ -51,4 +64,8 @@ func (s *Member) Set() { // object provider s.Object.UserPassword = viper.GetString("member.object.user_password") s.Object.AdminPassword = viper.GetString("member.object.admin_password") + + // multiuser provider + s.Multiuser.UserPassword = viper.GetString("member.multiuser.user_password") + s.Multiuser.AdminPassword = viper.GetString("member.multiuser.admin_password") } diff --git a/internal/member/manager.go b/internal/member/manager.go index 965ccf17..e717ecfe 100644 --- a/internal/member/manager.go +++ b/internal/member/manager.go @@ -10,6 +10,7 @@ import ( "github.com/demodesk/neko/internal/config" "github.com/demodesk/neko/internal/member/dummy" "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/types" ) @@ -26,6 +27,8 @@ func New(sessions types.SessionManager, config *config.Member) *MemberManagerCtx manager.provider = file.New(config.File) case "object": manager.provider = object.New(config.Object) + case "multiuser": + manager.provider = multiuser.New(config.Multiuser) case "dummy": fallthrough default: diff --git a/internal/member/multiuser/provider.go b/internal/member/multiuser/provider.go new file mode 100644 index 00000000..841e9c6d --- /dev/null +++ b/internal/member/multiuser/provider.go @@ -0,0 +1,96 @@ +package multiuser + +import ( + "errors" + "fmt" + + "github.com/demodesk/neko/pkg/types" + "github.com/demodesk/neko/pkg/utils" +) + +func New(config Config) types.MemberProvider { + return &MemberProviderCtx{ + config: config, + } +} + +type MemberProviderCtx struct { + config Config +} + +func (provider *MemberProviderCtx) Connect() error { + return nil +} + +func (provider *MemberProviderCtx) Disconnect() error { + return nil +} + +func (provider *MemberProviderCtx) Authenticate(username string, password string) (string, types.MemberProfile, error) { + // generate random token + token, err := utils.NewUID(5) + if err != nil { + return "", types.MemberProfile{}, err + } + + // id is username with token + id := fmt.Sprintf("%s-%s", username, token) + + // if logged in as administrator + if provider.config.AdminPassword == password { + return id, types.MemberProfile{ + Name: username, + IsAdmin: true, + CanLogin: true, + CanConnect: true, + CanWatch: true, + CanHost: true, + CanShareMedia: true, + CanAccessClipboard: true, + SendsInactiveCursor: true, + CanSeeInactiveCursors: true, + }, nil + } + + // if logged in as user + if provider.config.UserPassword == password { + return id, types.MemberProfile{ + Name: username, + IsAdmin: false, + CanLogin: true, + CanConnect: true, + CanWatch: true, + CanHost: true, + CanShareMedia: true, + CanAccessClipboard: true, + SendsInactiveCursor: true, + CanSeeInactiveCursors: false, + }, nil + } + + return "", types.MemberProfile{}, types.ErrMemberInvalidPassword +} + +func (provider *MemberProviderCtx) Insert(username string, password string, profile types.MemberProfile) (string, error) { + return "", errors.New("new user is created on first login in multiuser mode") +} + +func (provider *MemberProviderCtx) UpdateProfile(id string, profile types.MemberProfile) error { + return errors.New("cannot update user profile in multiuser mode") +} + +func (provider *MemberProviderCtx) UpdatePassword(id string, password string) error { + return errors.New("password can only be modified in config while in multiuser mode") +} + +func (provider *MemberProviderCtx) Select(id string) (types.MemberProfile, error) { + return types.MemberProfile{}, errors.New("cannot select user in multiuser mode") +} + +func (provider *MemberProviderCtx) SelectAll(limit int, offset int) (map[string]types.MemberProfile, error) { + return map[string]types.MemberProfile{}, errors.New("cannot select users in multiuser mode") +} + +func (provider *MemberProviderCtx) Delete(id string) error { + return errors.New("cannot delete user in multiuser mode") +} diff --git a/internal/member/multiuser/types.go b/internal/member/multiuser/types.go new file mode 100644 index 00000000..4d6103d9 --- /dev/null +++ b/internal/member/multiuser/types.go @@ -0,0 +1,6 @@ +package multiuser + +type Config struct { + AdminPassword string + UserPassword string +}