fix bug with user perms not being applied independantly

This commit is contained in:
Liam Stanley 2017-08-08 05:33:15 -04:00
parent 2b52b21176
commit b7e0086816
3 changed files with 83 additions and 18 deletions

View File

@ -485,7 +485,9 @@ func handleNAMES(c *Client, e Event) {
}
// Don't append modes, overwrite them.
user.Perms.set(modes, false)
perms, _ := user.Perms.Lookup(channel.Name)
perms.set(modes, false)
user.Perms.set(channel.Name, perms)
}
c.state.Unlock()
c.state.notify(c, UPDATE_STATE)

View File

@ -4,7 +4,11 @@
package girc
import "strings"
import (
"encoding/json"
"strings"
"sync"
)
// CMode represents a single step of a given mode change.
type CMode struct {
@ -353,7 +357,9 @@ func handleMODE(c *Client, e Event) {
user := c.state.lookupUser(modes[i].args)
if user != nil {
user.Perms.setFromMode(modes[i])
perms, _ := user.Perms.Lookup(channel.Name)
perms.setFromMode(modes[i])
user.Perms.set(channel.Name, perms)
}
}
@ -382,30 +388,83 @@ func (s *state) userPrefixes() string {
return DefaultPrefixes
}
// UserPerms contains all channel-based user permissions. The minimum op, and
// UserPerms contains all of the permissions for each channel the user is
// in.
type UserPerms struct {
mu sync.RWMutex
channels map[string]Perms
}
// Copy returns a deep copy of the channel permissions.
func (p *UserPerms) Copy() (perms *UserPerms) {
np := &UserPerms{
channels: make(map[string]Perms),
}
p.mu.RLock()
for key := range p.channels {
np.channels[key] = p.channels[key]
}
p.mu.RUnlock()
return np
}
// MarshalJSON implements json.Marshaler.
func (p *UserPerms) MarshalJSON() ([]byte, error) {
p.mu.Lock()
out, err := json.Marshal(&p.channels)
p.mu.Unlock()
return out, err
}
// Lookup looks up the users permissions for a given channel. ok is false
// if the user is not in the given channel.
func (p *UserPerms) Lookup(channel string) (perms Perms, ok bool) {
p.mu.RLock()
perms, ok = p.channels[ToRFC1459(channel)]
p.mu.RUnlock()
return perms, ok
}
func (p *UserPerms) set(channel string, perms Perms) {
p.mu.Lock()
p.channels[ToRFC1459(channel)] = perms
p.mu.Unlock()
}
func (p *UserPerms) remove(channel string) {
p.mu.Lock()
delete(p.channels, ToRFC1459(channel))
p.mu.Unlock()
}
// Perms contains all channel-based user permissions. The minimum op, and
// voice should be supported on all networks. This also supports non-rfc
// Owner, Admin, and HalfOp, if the network has support for it.
type UserPerms struct {
type Perms struct {
// Owner (non-rfc) indicates that the user has full permissions to the
// channel. More than one user can have owner permission.
Owner bool
Owner bool `json:"owner"`
// Admin (non-rfc) is commonly given to users that are trusted enough
// to manage channel permissions, as well as higher level service settings.
Admin bool
Admin bool `json:"admin"`
// Op is commonly given to trusted users who can manage a given channel
// by kicking, and banning users.
Op bool
Op bool `json:"op"`
// HalfOp (non-rfc) is commonly used to give users permissions like the
// ability to kick, without giving them greater abilities to ban all users.
HalfOp bool
HalfOp bool `json:"half_op"`
// Voice indicates the user has voice permissions, commonly given to known
// users, with very light trust, or to indicate a user is active.
Voice bool
Voice bool `json:"voice"`
}
// IsAdmin indicates that the user has banning abilities, and are likely a
// very trustable user (e.g. op+).
func (m UserPerms) IsAdmin() bool {
func (m Perms) IsAdmin() bool {
if m.Owner || m.Admin || m.Op {
return true
}
@ -415,7 +474,7 @@ func (m UserPerms) IsAdmin() bool {
// IsTrusted indicates that the user at least has modes set upon them, higher
// than a regular joining user.
func (m UserPerms) IsTrusted() bool {
func (m Perms) IsTrusted() bool {
if m.IsAdmin() || m.HalfOp || m.Voice {
return true
}
@ -424,7 +483,7 @@ func (m UserPerms) IsTrusted() bool {
}
// reset resets the modes of a user.
func (m *UserPerms) reset() {
func (m *Perms) reset() {
m.Owner = false
m.Admin = false
m.Op = false
@ -434,7 +493,7 @@ func (m *UserPerms) reset() {
// set translates raw prefix characters into proper permissions. Only
// use this function when you have a session lock.
func (m *UserPerms) set(prefix string, append bool) {
func (m *Perms) set(prefix string, append bool) {
if !append {
m.reset()
}
@ -457,7 +516,7 @@ func (m *UserPerms) set(prefix string, append bool) {
// setFromMode sets user-permissions based on channel user mode chars. E.g.
// "o" being oper, "v" being voice, etc.
func (m *UserPerms) setFromMode(mode CMode) {
func (m *Perms) setFromMode(mode CMode) {
switch string(mode.name) {
case ModeOwner:
m.Owner = mode.add

View File

@ -83,9 +83,7 @@ type User struct {
// Perms are the user permissions applied to this user that affect the given
// channel. This supports non-rfc style modes like Admin, Owner, and HalfOp.
// If you want to easily check if a user has permissions equal or greater
// than OP, use Perms.IsAdmin().
Perms UserPerms
Perms *UserPerms
// Extras are things added on by additional tracking methods, which may
// or may not work on the IRC server in mention.
@ -113,6 +111,7 @@ func (u *User) Copy() *User {
nu := &User{}
*nu = *u
nu.Perms = u.Perms.Copy()
_ = copy(nu.Channels, u.Channels)
return nu
@ -122,6 +121,8 @@ func (u *User) Copy() *User {
func (u *User) addChannel(name string) {
u.Channels = append(u.Channels, ToRFC1459(name))
sort.StringsAreSorted(u.Channels)
u.Perms.set(name, Perms{})
}
// deleteChannel removes an existing channel from the users channel list.
@ -139,6 +140,8 @@ func (u *User) deleteChannel(name string) {
if j != -1 {
u.Channels = append(u.Channels[:j], u.Channels[j+1:]...)
}
u.Perms.remove(name)
}
// InChannel checks to see if a user is in the given channel.
@ -312,6 +315,7 @@ func (s *state) createUser(nick string) (ok bool) {
Nick: nick,
FirstSeen: time.Now(),
LastActive: time.Now(),
Perms: &UserPerms{channels: make(map[string]Perms)},
}
return true