remove members from session.

This commit is contained in:
Miroslav Šedivý 2021-03-13 21:11:48 +01:00
parent 84f0b0aaeb
commit 3aea0c7bf5
9 changed files with 96 additions and 231 deletions

View File

@ -14,7 +14,7 @@ type MemberDataPayload struct {
func (h *MembersHandler) membersList(w http.ResponseWriter, r *http.Request) {
members := []MemberDataPayload{}
for _, session := range h.sessions.Members() {
for _, session := range h.sessions.List() {
profile := session.GetProfile()
members = append(members, MemberDataPayload{
ID: session.ID(),

View File

@ -30,12 +30,23 @@ func (api *ApiManagerCtx) Login(w http.ResponseWriter, r *http.Request) {
return
}
token := data.Secret
// TODO: Proper login.
//session, err := api.sessions.Authenticate(data.ID, data.Secret)
//if err != nil {
utils.HttpUnauthorized(w, "no authentication implemented")
session, err := api.sessions.Create(token, types.MemberProfile{
Name: data.ID,
IsAdmin: true,
CanLogin: true,
CanConnect: true,
CanWatch: true,
CanHost: true,
CanAccessClipboard: true,
})
if err != nil {
utils.HttpUnauthorized(w, err)
return
//}
}
sameSite := http.SameSiteNoneMode
if UnsecureCookies {
@ -43,17 +54,8 @@ func (api *ApiManagerCtx) Login(w http.ResponseWriter, r *http.Request) {
}
http.SetCookie(w, &http.Cookie{
Name: "neko-id",
Value: session.ID(),
Expires: CookieExpirationDate,
Secure: !UnsecureCookies,
SameSite: sameSite,
HttpOnly: false,
})
http.SetCookie(w, &http.Cookie{
Name: "neko-secret",
Value: data.Secret,
Name: "NEKO_SESSION",
Value: token,
Expires: CookieExpirationDate,
Secure: !UnsecureCookies,
SameSite: sameSite,
@ -68,22 +70,22 @@ func (api *ApiManagerCtx) Login(w http.ResponseWriter, r *http.Request) {
}
func (api *ApiManagerCtx) Logout(w http.ResponseWriter, r *http.Request) {
session := auth.GetSession(r)
// TODO: Proper logout.
err := api.sessions.Delete(session.ID())
if err != nil {
utils.HttpUnauthorized(w, err)
return
}
sameSite := http.SameSiteNoneMode
if UnsecureCookies {
sameSite = http.SameSiteDefaultMode
}
http.SetCookie(w, &http.Cookie{
Name: "neko-id",
Value: "",
Expires: time.Unix(0, 0),
Secure: !UnsecureCookies,
SameSite: sameSite,
HttpOnly: false,
})
http.SetCookie(w, &http.Cookie{
Name: "neko-secret",
Name: "NEKO_SESSION",
Value: "",
Expires: time.Unix(0, 0),
Secure: !UnsecureCookies,

View File

@ -6,46 +6,18 @@ import (
)
type Session struct {
Password string
AdminPassword string
ImplicitHosting bool
DatabaseAdapter string
FilePath string
}
func (Session) Init(cmd *cobra.Command) error {
cmd.PersistentFlags().String("password", "neko", "password for connecting to stream")
if err := viper.BindPFlag("password", cmd.PersistentFlags().Lookup("password")); err != nil {
return err
}
cmd.PersistentFlags().String("password_admin", "admin", "admin password for connecting to stream")
if err := viper.BindPFlag("password_admin", cmd.PersistentFlags().Lookup("password_admin")); err != nil {
return err
}
cmd.PersistentFlags().Bool("implicit_hosting", true, "allow implicit control switching")
if err := viper.BindPFlag("implicit_hosting", cmd.PersistentFlags().Lookup("implicit_hosting")); err != nil {
return err
}
cmd.PersistentFlags().String("database_adapter", "file", "choose database adapter for members")
if err := viper.BindPFlag("database_adapter", cmd.PersistentFlags().Lookup("database_adapter")); err != nil {
return err
}
cmd.PersistentFlags().String("file_path", "/home/neko/members.json", "file adapter: specify file path")
if err := viper.BindPFlag("file_path", cmd.PersistentFlags().Lookup("file_path")); err != nil {
return err
}
return nil
}
func (s *Session) Set() {
s.Password = viper.GetString("password")
s.AdminPassword = viper.GetString("password_admin")
s.ImplicitHosting = viper.GetBool("implicit_hosting")
s.DatabaseAdapter = viper.GetString("database_adapter")
s.FilePath = viper.GetString("file_path")
}

View File

@ -24,7 +24,7 @@ func (manager *SessionManagerCtx) Authenticate(r *http.Request) (types.Session,
func getToken(r *http.Request) (string, bool) {
// get from Cookie
cookie, err := r.Cookie("neko-token")
cookie, err := r.Cookie("NEKO_SESSION")
if err == nil {
return cookie.Value, true
}

View File

@ -9,37 +9,45 @@ import (
"github.com/rs/zerolog/log"
"demodesk/neko/internal/config"
"demodesk/neko/internal/session/database"
"demodesk/neko/internal/types"
"demodesk/neko/internal/utils"
)
func New(config *config.Session) *SessionManagerCtx {
return &SessionManagerCtx{
logger: log.With().Str("module", "session").Logger(),
host: nil,
hostMu: sync.Mutex{},
config: config,
database: database.New(config),
members: make(map[string]*SessionCtx),
membersMu: sync.Mutex{},
emmiter: events.New(),
logger: log.With().Str("module", "session").Logger(),
config: config,
host: nil,
hostMu: sync.Mutex{},
sessions: make(map[string]*SessionCtx),
sessionsMu: sync.Mutex{},
emmiter: events.New(),
}
}
type SessionManagerCtx struct {
logger zerolog.Logger
host types.Session
hostMu sync.Mutex
config *config.Session
database types.MembersDatabase
members map[string]*SessionCtx
membersMu sync.Mutex
emmiter events.EventEmmiter
logger zerolog.Logger
config *config.Session
host types.Session
hostMu sync.Mutex
sessions map[string]*SessionCtx
sessionsMu sync.Mutex
emmiter events.EventEmmiter
}
// TODO: Extract members map + primitives.
func (manager *SessionManagerCtx) add(id string, profile types.MemberProfile) types.Session {
// ---
// sessions
// ---
func (manager *SessionManagerCtx) Create(id string, profile types.MemberProfile) (types.Session, error) {
manager.sessionsMu.Lock()
_, ok := manager.sessions[id]
if ok {
manager.sessionsMu.Unlock()
return nil, fmt.Errorf("Session id already exists.")
}
session := &SessionCtx{
id: id,
manager: manager,
@ -47,104 +55,24 @@ func (manager *SessionManagerCtx) add(id string, profile types.MemberProfile) ty
profile: profile,
}
manager.members[id] = session
return session
}
// ---
// members
// ---
func (manager *SessionManagerCtx) Connect() error {
if err := manager.database.Connect(); err != nil {
return err
}
profiles, err := manager.database.Select()
if err != nil {
return err
}
for id, profile := range profiles {
_ = manager.add(id, profile)
}
// TODO: Move to Database, or make `admin` as reserved ID.
// create default admin account at startup
_ = manager.add("admin", types.MemberProfile{
Secret: manager.config.AdminPassword,
Name: "Administrator",
IsAdmin: true,
CanLogin: true,
CanConnect: true,
CanWatch: true,
CanHost: true,
CanAccessClipboard: true,
})
// create default user account at startup
_ = manager.add("user", types.MemberProfile{
Secret: manager.config.Password,
Name: "User",
IsAdmin: false,
CanLogin: true,
CanConnect: true,
CanWatch: true,
CanHost: true,
CanAccessClipboard: true,
})
return nil
}
func (manager *SessionManagerCtx) Disconnect() error {
return manager.database.Disconnect()
}
func (manager *SessionManagerCtx) Create(id string, profile types.MemberProfile) (types.Session, error) {
manager.membersMu.Lock()
_, ok := manager.members[id]
if ok {
manager.membersMu.Unlock()
return nil, fmt.Errorf("Member ID already exists.")
}
err := manager.database.Insert(id, profile)
if err != nil {
manager.membersMu.Unlock()
return nil, err
}
session := manager.add(id, profile)
manager.membersMu.Unlock()
manager.sessions[id] = session
manager.sessionsMu.Unlock()
manager.emmiter.Emit("created", session)
return session, nil
}
func (manager *SessionManagerCtx) Update(id string, profile types.MemberProfile) error {
manager.membersMu.Lock()
manager.sessionsMu.Lock()
session, ok := manager.members[id]
session, ok := manager.sessions[id]
if !ok {
manager.membersMu.Unlock()
return fmt.Errorf("Member not found.")
}
// preserve secret if not updated
if profile.Secret == "" {
profile.Secret = session.profile.Secret
}
err := manager.database.Update(id, profile)
if err != nil {
manager.membersMu.Unlock()
return err
manager.sessionsMu.Unlock()
return fmt.Errorf("Session id not found.")
}
session.profile = profile
manager.membersMu.Unlock()
manager.sessionsMu.Unlock()
manager.emmiter.Emit("profile_changed", session)
session.profileChanged()
@ -152,24 +80,19 @@ func (manager *SessionManagerCtx) Update(id string, profile types.MemberProfile)
}
func (manager *SessionManagerCtx) Delete(id string) error {
manager.membersMu.Lock()
session, ok := manager.members[id]
manager.sessionsMu.Lock()
session, ok := manager.sessions[id]
if !ok {
manager.membersMu.Unlock()
return fmt.Errorf("Member not found.")
manager.sessionsMu.Unlock()
return fmt.Errorf("Session id not found.")
}
err := manager.database.Delete(id)
if err != nil {
manager.membersMu.Unlock()
return err
}
delete(manager.members, id)
manager.membersMu.Unlock()
delete(manager.sessions, id)
manager.sessionsMu.Unlock()
var err error
if session.IsConnected() {
err = session.Disconnect("member deleted")
err = session.Disconnect("session deleted")
}
manager.emmiter.Emit("deleted", session)
@ -177,13 +100,25 @@ func (manager *SessionManagerCtx) Delete(id string) error {
}
func (manager *SessionManagerCtx) Get(id string) (types.Session, bool) {
manager.membersMu.Lock()
defer manager.membersMu.Unlock()
manager.sessionsMu.Lock()
defer manager.sessionsMu.Unlock()
session, ok := manager.members[id]
session, ok := manager.sessions[id]
return session, ok
}
func (manager *SessionManagerCtx) List() []types.Session {
manager.sessionsMu.Lock()
defer manager.sessionsMu.Unlock()
var sessions []types.Session
for _, session := range manager.sessions {
sessions = append(sessions, session)
}
return sessions
}
// ---
// host
// ---
@ -213,39 +148,14 @@ func (manager *SessionManagerCtx) ClearHost() {
}
// ---
// members list
// broadcasts
// ---
func (manager *SessionManagerCtx) HasConnectedMembers() bool {
manager.membersMu.Lock()
defer manager.membersMu.Unlock()
for _, session := range manager.members {
if session.IsConnected() {
return true
}
}
return false
}
func (manager *SessionManagerCtx) Members() []types.Session {
manager.membersMu.Lock()
defer manager.membersMu.Unlock()
var sessions []types.Session
for _, session := range manager.members {
sessions = append(sessions, session)
}
return sessions
}
func (manager *SessionManagerCtx) Broadcast(v interface{}, exclude interface{}) {
manager.membersMu.Lock()
defer manager.membersMu.Unlock()
manager.sessionsMu.Lock()
defer manager.sessionsMu.Unlock()
for id, session := range manager.members {
for id, session := range manager.sessions {
if !session.IsConnected() {
continue
}
@ -263,10 +173,10 @@ func (manager *SessionManagerCtx) Broadcast(v interface{}, exclude interface{})
}
func (manager *SessionManagerCtx) AdminBroadcast(v interface{}, exclude interface{}) {
manager.membersMu.Lock()
defer manager.membersMu.Unlock()
manager.sessionsMu.Lock()
defer manager.sessionsMu.Unlock()
for id, session := range manager.members {
for id, session := range manager.sessions {
if !session.IsConnected() || !session.IsAdmin() {
continue
}

View File

@ -26,10 +26,6 @@ func (session *SessionCtx) ID() string {
// profile
// ---
func (session *SessionCtx) VerifySecret(secret string) bool {
return session.profile.Secret == secret
}
func (session *SessionCtx) Name() string {
return session.profile.Name
}

View File

@ -32,7 +32,6 @@ type Session interface {
ID() string
// profile
VerifySecret(secret string) bool
Name() string
IsAdmin() bool
CanLogin() bool
@ -60,20 +59,16 @@ type Session interface {
}
type SessionManager interface {
Connect() error
Disconnect() error
Create(id string, profile MemberProfile) (Session, error)
Update(id string, profile MemberProfile) error
Get(id string) (Session, bool)
Delete(id string) error
List() []Session
SetHost(host Session)
GetHost() Session
ClearHost()
HasConnectedMembers() bool
Members() []Session
Broadcast(v interface{}, exclude interface{})
AdminBroadcast(v interface{}, exclude interface{})
@ -88,6 +83,5 @@ type SessionManager interface {
ImplicitHosting() bool
AuthenticateRequest(r *http.Request) (Session, error)
Authenticate(id string, secret string) (Session, error)
Authenticate(r *http.Request) (Session, error)
}

View File

@ -24,7 +24,7 @@ func (h *MessageHandlerCtx) systemInit(session types.Session) error {
}
members := map[string]message.MemberData{}
for _, session := range h.sessions.Members() {
for _, session := range h.sessions.List() {
members[session.ID()] = message.MemberData{
ID: session.ID(),
Profile: session.GetProfile(),

View File

@ -132,9 +132,6 @@ func (neko *Neko) Start() {
neko.sessionManager = session.New(
neko.Configs.Session,
)
if err := neko.sessionManager.Connect(); err != nil {
neko.logger.Panic().Err(err).Msg("unable to connect to session manager")
}
neko.desktopManager = desktop.New(
neko.Configs.Desktop,
@ -184,12 +181,6 @@ func (neko *Neko) Start() {
}
func (neko *Neko) Shutdown() {
if err := neko.sessionManager.Disconnect(); err != nil {
neko.logger.Err(err).Msg("session manager disconnect with an error")
} else {
neko.logger.Debug().Msg("session manager disconnect")
}
if err := neko.desktopManager.Shutdown(); err != nil {
neko.logger.Err(err).Msg("desktop manager shutdown with an error")
} else {