mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
remove members from session.
This commit is contained in:
parent
84f0b0aaeb
commit
3aea0c7bf5
@ -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(),
|
||||
|
@ -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,
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"demodesk/neko/internal/config"
|
||||
"demodesk/neko/internal/session/database"
|
||||
"demodesk/neko/internal/types"
|
||||
"demodesk/neko/internal/utils"
|
||||
)
|
||||
@ -17,29 +16,38 @@ import (
|
||||
func New(config *config.Session) *SessionManagerCtx {
|
||||
return &SessionManagerCtx{
|
||||
logger: log.With().Str("module", "session").Logger(),
|
||||
config: config,
|
||||
host: nil,
|
||||
hostMu: sync.Mutex{},
|
||||
config: config,
|
||||
database: database.New(config),
|
||||
members: make(map[string]*SessionCtx),
|
||||
membersMu: sync.Mutex{},
|
||||
sessions: make(map[string]*SessionCtx),
|
||||
sessionsMu: sync.Mutex{},
|
||||
emmiter: events.New(),
|
||||
}
|
||||
}
|
||||
|
||||
type SessionManagerCtx struct {
|
||||
logger zerolog.Logger
|
||||
config *config.Session
|
||||
host types.Session
|
||||
hostMu sync.Mutex
|
||||
config *config.Session
|
||||
database types.MembersDatabase
|
||||
members map[string]*SessionCtx
|
||||
membersMu 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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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(),
|
||||
|
9
neko.go
9
neko.go
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user