1
Fork 0

Implement message permission and shutup command.

This commit is contained in:
Juliusz Chroboczek 2024-05-08 16:00:18 +02:00
parent 2b145317a5
commit 1315084185
9 changed files with 85 additions and 38 deletions

View File

@ -17,6 +17,8 @@ Galene 0.9 (unreleased)
* Implemented a contextual menu that triggers on a double click on
a chat entry.
* Added a new command "/stopshare".
* Added a new permission "message" and new commands "shutup" and
"unshutup".
14 April 2024: Galene 0.8.2

2
README
View File

@ -162,7 +162,7 @@ nobody will be able to join the group. The following fields are allowed:
- `users`: is a dictionary that maps user names to dictionaries with
entries `password` and `permissions`; `permissions` should be one of
`op`, `present` or `passive`;
`op`, `present`, `message` or `observe`.
- `wildcard-user` is a dictionaries with entries `password` and `permissions`
that will be used for usernames with no matching entry in the `users`
dictionary;

View File

@ -24,8 +24,9 @@ type Permissions struct {
}
var permissionsMap = map[string][]string{
"op": []string{"op", "present", "token"},
"present": []string{"present"},
"op": []string{"op", "present", "message", "token"},
"present": []string{"present", "message"},
"message": []string{"message"},
"observe": []string{},
"admin": []string{"admin"},
}
@ -528,7 +529,7 @@ func upgradeDescription(desc *Description) error {
desc.Presenter = nil
}
if desc.Other != nil {
upgradeUsers(desc.Other, "observe")
upgradeUsers(desc.Other, "message")
desc.Other = nil
}

View File

@ -63,11 +63,11 @@ var descJSON = `
"users": {
"jch": {"password": "topsecret", "permissions": "op"},
"john": {"password": "secret", "permissions": "present"},
"james": {"password": "secret2", "permissions": "observe"},
"james": {"password": "secret2", "permissions": "message"},
"peter": {"password": "secret4"}
},
"wildcard-user":
{"permissions": "observe", "password": {"type":"wildcard"}}
{"permissions": "message", "password": {"type":"wildcard"}}
}`
func TestDescriptionJSON(t *testing.T) {
@ -139,6 +139,10 @@ func TestUpgradeDescription(t *testing.T) {
}
for k, v1 := range d1.Users {
if k == "peter" {
// not representable in the old format
continue
}
v2 := d2.Users[k]
if !reflect.DeepEqual(v1.Password, v2.Password) ||
!permissionsEqual(

View File

@ -114,19 +114,19 @@ type credPerm struct {
var goodClients = []credPerm{
{
ClientCredentials{Username: &jch, Password: "topsecret"},
[]string{"op", "present", "token"},
[]string{"op", "present", "message", "token"},
},
{
ClientCredentials{Username: &john, Password: "secret"},
[]string{"present"},
[]string{"present", "message"},
},
{
ClientCredentials{Username: &james, Password: "secret2"},
[]string{},
[]string{"message"},
},
{
ClientCredentials{Username: &paul, Password: "secret3"},
[]string{},
[]string{"message"},
},
{
ClientCredentials{Username: &peter, Password: "secret4"},
@ -189,29 +189,29 @@ func TestExtraPermissions(t *testing.T) {
}
}
doit("jch", []string{"op", "token", "present"})
doit("john", []string{"present"})
doit("jch", []string{"op", "token", "present", "message"})
doit("john", []string{"present", "message"})
doit("james", []string{})
d.AllowRecording = true
d.UnrestrictedTokens = false
doit("jch", []string{"op", "record", "token", "present"})
doit("john", []string{"present"})
doit("jch", []string{"op", "record", "token", "present", "message"})
doit("john", []string{"present", "message"})
doit("james", []string{})
d.AllowRecording = false
d.UnrestrictedTokens = true
doit("jch", []string{"op", "token", "present"})
doit("john", []string{"token", "present"})
doit("jch", []string{"op", "token", "present", "message"})
doit("john", []string{"token", "present", "message"})
doit("james", []string{})
d.AllowRecording = true
d.UnrestrictedTokens = true
doit("jch", []string{"op", "record", "token", "present"})
doit("john", []string{"token", "present"})
doit("jch", []string{"op", "record", "token", "present", "message"})
doit("john", []string{"token", "present", "message"})
doit("james", []string{})
}

View File

@ -1349,6 +1349,10 @@ func setPermissions(g *group.Group, id string, perm string) error {
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")
}
@ -1570,6 +1574,10 @@ func handleClientMessage(c *webClient, m clientMessage) error {
return c.error(group.UserError("join a group first"))
}
if !member("message", c.permissions) {
return c.error(group.UserError("not authorised"))
}
now := time.Now()
if m.Type == "chat" {
@ -1855,7 +1863,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
return c.error(group.UserError("join a group first"))
}
switch m.Kind {
case "op", "unop", "present", "unpresent":
case "op", "unop", "present", "unpresent", "shutup", "unshutup":
if !member("op", c.permissions) {
return c.error(group.UserError("not authorised"))
}

View File

@ -3288,10 +3288,13 @@ function makeToken(template) {
v["not-before"] = template["not-before"];
if('permissions' in template)
v.permissions = template.permissions;
else if(serverConnection.permissions.indexOf('present') >= 0)
v.permissions = ['present'];
else
else {
v.permissions = [];
if(serverConnection.permissions.indexOf('present') >= 0)
v.permissions.push('present');
if(serverConnection.permissions.indexOf('message') >= 0)
v.permissions.push('message');
}
serverConnection.groupAction('maketoken', v);
}
@ -3520,6 +3523,20 @@ commands.unpresent = {
f: userCommand,
};
commands.shutup = {
parameters: 'user',
description: 'revoke the right to send chat messages',
predicate: operatorPredicate,
f: userCommand,
};
commands.unshutup = {
parameters: 'user',
description: 'give the right to send chat messages',
predicate: operatorPredicate,
f: userCommand,
};
commands.mute = {
parameters: 'user',
description: 'mute a remote user',

View File

@ -106,6 +106,15 @@ func (token *Stateful) Check(host, group string, username *string) (string, []st
return user, token.Permissions, nil
}
func member(v string, l []string) bool {
for _, w := range l {
if v == w {
return true
}
}
return false
}
// load updates the state from the corresponding file.
// called locked
func (state *state) load() (string, error) {
@ -155,6 +164,12 @@ func (state *state) load() (string, error) {
state.fileSize = 0
return "", err
}
// the "message" permission was introduced in Galene 0.9,
// so add it to tokens read from disk. We can remove this
// hack in late 2024.
if !member("message", t.Permissions) {
t.Permissions = append(t.Permissions, "message")
}
ts[t.Token] = &t
}
state.tokens = ts

View File

@ -48,27 +48,27 @@ func TestStatefulCheck(t *testing.T) {
Token: "token",
Group: "group",
Username: &user,
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &future,
}
token2 := &Stateful{
Token: "token",
Group: "group",
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &future,
}
token3 := &Stateful{
Token: "token",
Group: "group",
Username: &user,
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &past,
}
token4 := &Stateful{
Token: "token",
Group: "group",
Username: &user,
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &future,
NotBefore: &nearFuture,
}
@ -85,27 +85,27 @@ func TestStatefulCheck(t *testing.T) {
group: "group",
username: &user,
expUsername: user,
expPermissions: []string{"present"},
expPermissions: []string{"present", "message"},
},
{
token: token1,
group: "group",
username: &user2,
expUsername: user,
expPermissions: []string{"present"},
expPermissions: []string{"present", "message"},
},
{
token: token1,
group: "group",
expUsername: user,
expPermissions: []string{"present"},
expPermissions: []string{"present", "message"},
},
{
token: token2,
group: "group",
username: &user,
expUsername: "",
expPermissions: []string{"present"},
expPermissions: []string{"present", "message"},
},
}
@ -232,14 +232,14 @@ func TestTokenStorage(t *testing.T) {
Token: "tok1",
Group: "test",
Username: &user1,
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &future,
},
&Stateful{
Token: "tok2",
Group: "test",
Username: &user2,
Permissions: []string{"present", "record"},
Permissions: []string{"present", "record", "message"},
Expires: &nearFuture,
NotBefore: &past,
},
@ -247,7 +247,7 @@ func TestTokenStorage(t *testing.T) {
Token: "tok3",
Group: "test",
Username: &user3,
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &nearFuture,
},
}
@ -327,35 +327,35 @@ func TestExpire(t *testing.T) {
Token: "tok1",
Group: "test",
Username: &user,
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &now,
},
&Stateful{
Token: "tok2",
Group: "test",
Username: &user,
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &future,
},
&Stateful{
Token: "tok3",
Group: "test",
Username: &user,
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &now,
},
&Stateful{
Token: "tok4",
Group: "test",
Username: &user,
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &past,
},
&Stateful{
Token: "tok5",
Group: "test",
Username: &user,
Permissions: []string{"present"},
Permissions: []string{"present", "message"},
Expires: &longPast,
},
}