Archived
2
0

added control protection.

This commit is contained in:
Miroslav Šedivý 2021-11-16 23:48:40 +01:00
parent 00201af40c
commit e2ba39922c
4 changed files with 54 additions and 0 deletions

View File

@ -5,6 +5,7 @@
### New Features ### New Features
- Lock controls for users, globally. - Lock controls for users, globally.
- Ability to set locks from config `NEKO_LOCKS=control login`. - Ability to set locks from config `NEKO_LOCKS=control login`.
- Added control protection - users can gain control only if at least one admin is in the room `NEKO_CONTROL_PROTECTION=true`.
### Misc ### Misc
- ARM-based images not bound to Raspberry Pi only. - ARM-based images not bound to Raspberry Pi only.

View File

@ -68,6 +68,9 @@ NEKO_ICESERVERS:
NEKO_LOCKS: NEKO_LOCKS:
- Resources, that will be locked when starting, separated by whitespace. - Resources, that will be locked when starting, separated by whitespace.
- Currently supported: control login - Currently supported: control login
NEKO_CONTROL_PROTECTION:
- Control protection means, users can gain control only if at least one admin is in the room.
- e.g. false
``` ```
## Agruments ## Agruments

View File

@ -10,6 +10,8 @@ type WebSocket struct {
AdminPassword string AdminPassword string
Proxy bool Proxy bool
Locks []string Locks []string
ControlProtection bool
} }
func (WebSocket) Init(cmd *cobra.Command) error { func (WebSocket) Init(cmd *cobra.Command) error {
@ -33,6 +35,11 @@ func (WebSocket) Init(cmd *cobra.Command) error {
return err return err
} }
cmd.PersistentFlags().Bool("control_protection", true, "control protection means, users can gain control only if at least one admin is in the room")
if err := viper.BindPFlag("control_protection", cmd.PersistentFlags().Lookup("control_protection")); err != nil {
return err
}
return nil return nil
} }
@ -41,4 +48,6 @@ func (s *WebSocket) Set() {
s.AdminPassword = viper.GetString("password_admin") s.AdminPassword = viper.GetString("password_admin")
s.Proxy = viper.GetBool("proxy") s.Proxy = viper.GetBool("proxy")
s.Locks = viper.GetStringSlice("locks") s.Locks = viper.GetStringSlice("locks")
s.ControlProtection = viper.GetBool("control_protection")
} }

View File

@ -18,6 +18,8 @@ import (
"m1k1o/neko/internal/utils" "m1k1o/neko/internal/utils"
) )
const CONTROL_PROTECTION_SESSION = "control_protection"
func New(sessions types.SessionManager, remote types.RemoteManager, broadcast types.BroadcastManager, webrtc types.WebRTCManager, conf *config.WebSocket) *WebSocketHandler { func New(sessions types.SessionManager, remote types.RemoteManager, broadcast types.BroadcastManager, webrtc types.WebRTCManager, conf *config.WebSocket) *WebSocketHandler {
logger := log.With().Str("module", "websocket").Logger() logger := log.With().Str("module", "websocket").Logger()
@ -30,6 +32,12 @@ func New(sessions types.SessionManager, remote types.RemoteManager, broadcast ty
logger.Info().Msgf("locked resources: %+v", conf.Locks) logger.Info().Msgf("locked resources: %+v", conf.Locks)
} }
// if control protection is enabled
if conf.ControlProtection {
locks["control"] = CONTROL_PROTECTION_SESSION
logger.Info().Msgf("control locked on behalf of control protection")
}
return &WebSocketHandler{ return &WebSocketHandler{
logger: logger, logger: logger,
shutdown: make(chan interface{}), shutdown: make(chan interface{}),
@ -84,6 +92,23 @@ func (ws *WebSocketHandler) Start() {
} else { } else {
ws.logger.Debug().Str("id", id).Msg("session connected") ws.logger.Debug().Str("id", id).Msg("session connected")
} }
// if control protection is enabled and at least one admin
// and if room was locked on behalf control protection, unlock
sess, ok := ws.handler.locked["control"]
if ok && ws.conf.ControlProtection && sess == CONTROL_PROTECTION_SESSION && len(ws.sessions.Admins()) > 0 {
delete(ws.handler.locked, "control")
ws.logger.Info().Msgf("control unlocked on behalf of control protection")
if err := ws.sessions.Broadcast(
message.AdminLock{
Event: event.ADMIN_UNLOCK,
ID: id,
Resource: "control",
}, nil); err != nil {
ws.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.ADMIN_UNLOCK)
}
}
}) })
ws.sessions.OnDestroy(func(id string, session types.Session) { ws.sessions.OnDestroy(func(id string, session types.Session) {
@ -92,6 +117,22 @@ func (ws *WebSocketHandler) Start() {
} else { } else {
ws.logger.Debug().Str("id", id).Msg("session destroyed") ws.logger.Debug().Str("id", id).Msg("session destroyed")
} }
// if control protection is enabled and no admin
if ws.conf.ControlProtection && len(ws.sessions.Admins()) == 0 {
ws.handler.locked["control"] = CONTROL_PROTECTION_SESSION
ws.logger.Info().Msgf("control locked and released on behalf of control protection")
ws.handler.adminRelease(id, session)
if err := ws.sessions.Broadcast(
message.AdminLock{
Event: event.ADMIN_LOCK,
ID: id,
Resource: "control",
}, nil); err != nil {
ws.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.ADMIN_LOCK)
}
}
}) })
ws.wg.Add(1) ws.wg.Add(1)