Use message passing for changing permissions.
We used to handle permission change commands by directly mutating the permissions field from the source client's thread, which is racy. We now use message passing. Thanks to Vinayak Mishra.
This commit is contained in:
+37
-38
@@ -922,6 +922,10 @@ type pushClientAction struct {
|
|||||||
data map[string]interface{}
|
data map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type changePermissionsAction struct {
|
||||||
|
kind string
|
||||||
|
}
|
||||||
|
|
||||||
type permissionsChangedAction struct{}
|
type permissionsChangedAction struct{}
|
||||||
|
|
||||||
type joinedAction struct {
|
type joinedAction struct {
|
||||||
@@ -1222,6 +1226,29 @@ func handleAction(c *webClient, a any) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case changePermissionsAction:
|
||||||
|
switch a.kind {
|
||||||
|
case "op":
|
||||||
|
c.permissions = addnew("op", c.permissions)
|
||||||
|
g := c.Group()
|
||||||
|
if g != nil && g.Description().AllowRecording {
|
||||||
|
c.permissions = addnew("record", c.permissions)
|
||||||
|
}
|
||||||
|
case "unop":
|
||||||
|
c.permissions = remove("op", c.permissions)
|
||||||
|
c.permissions = remove("record", c.permissions)
|
||||||
|
case "present":
|
||||||
|
c.permissions = addnew("present", c.permissions)
|
||||||
|
case "unpresent":
|
||||||
|
c.permissions = remove("present", c.permissions)
|
||||||
|
case "shutup":
|
||||||
|
c.permissions = remove("message", c.permissions)
|
||||||
|
case "unshutup":
|
||||||
|
c.permissions = addnew("message", c.permissions)
|
||||||
|
default:
|
||||||
|
return group.UserError("unknown permission")
|
||||||
|
}
|
||||||
|
c.action(permissionsChangedAction{})
|
||||||
case permissionsChangedAction:
|
case permissionsChangedAction:
|
||||||
g := c.Group()
|
g := c.Group()
|
||||||
if g == nil {
|
if g == nil {
|
||||||
@@ -1338,41 +1365,6 @@ func closeDownConn(c *webClient, id string, message string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPermissions(g *group.Group, id string, perm string) error {
|
|
||||||
client := g.GetClient(id)
|
|
||||||
if client == nil {
|
|
||||||
return group.UserError("no such user")
|
|
||||||
}
|
|
||||||
|
|
||||||
c, ok := client.(*webClient)
|
|
||||||
if !ok {
|
|
||||||
return group.UserError("this is not a real user")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch perm {
|
|
||||||
case "op":
|
|
||||||
c.permissions = addnew("op", c.permissions)
|
|
||||||
if g.Description().AllowRecording {
|
|
||||||
c.permissions = addnew("record", c.permissions)
|
|
||||||
}
|
|
||||||
case "unop":
|
|
||||||
c.permissions = remove("op", c.permissions)
|
|
||||||
c.permissions = remove("record", c.permissions)
|
|
||||||
case "present":
|
|
||||||
c.permissions = addnew("present", c.permissions)
|
|
||||||
case "unpresent":
|
|
||||||
c.permissions = remove("present", c.permissions)
|
|
||||||
case "shutup":
|
|
||||||
c.permissions = remove("message", c.permissions)
|
|
||||||
case "unshutup":
|
|
||||||
c.permissions = addnew("message", c.permissions)
|
|
||||||
default:
|
|
||||||
return group.UserError("unknown permission")
|
|
||||||
}
|
|
||||||
c.action(permissionsChangedAction{})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *webClient) Kick(id string, user *string, message string) error {
|
func (c *webClient) Kick(id string, user *string, message string) error {
|
||||||
c.action(kickAction{id, user, message})
|
c.action(kickAction{id, user, message})
|
||||||
return nil
|
return nil
|
||||||
@@ -1912,10 +1904,17 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
|||||||
if !member("op", c.permissions) {
|
if !member("op", c.permissions) {
|
||||||
return c.error(group.UserError("not authorised"))
|
return c.error(group.UserError("not authorised"))
|
||||||
}
|
}
|
||||||
err := setPermissions(g, m.Dest, m.Kind)
|
t := g.GetClient(m.Dest)
|
||||||
if err != nil {
|
if t == nil {
|
||||||
return c.error(err)
|
return c.error(group.UserError("no suck user"))
|
||||||
}
|
}
|
||||||
|
target, ok := t.(*webClient)
|
||||||
|
if !ok {
|
||||||
|
return c.error(group.UserError(
|
||||||
|
"this is not a real user",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
target.action(changePermissionsAction{m.Kind})
|
||||||
case "identify":
|
case "identify":
|
||||||
if !member("op", c.permissions) {
|
if !member("op", c.permissions) {
|
||||||
return c.error(group.UserError("not authorised"))
|
return c.error(group.UserError("not authorised"))
|
||||||
|
|||||||
Reference in New Issue
Block a user