Add canView to chat & fix admin role

This commit is contained in:
Andrea Maria Piana 2024-03-19 17:14:24 +00:00 committed by Jonathan Rainville
parent ade85df3a5
commit 894eb5758e
4 changed files with 92 additions and 21 deletions

View File

@ -104,6 +104,7 @@ type CommunityChat struct {
Members map[string]*protobuf.CommunityMember `json:"members"` Members map[string]*protobuf.CommunityMember `json:"members"`
Permissions *protobuf.CommunityPermissions `json:"permissions"` Permissions *protobuf.CommunityPermissions `json:"permissions"`
CanPost bool `json:"canPost"` CanPost bool `json:"canPost"`
CanView bool `json:"canView"`
ViewersCanPostReactions bool `json:"viewersCanPostReactions"` ViewersCanPostReactions bool `json:"viewersCanPostReactions"`
Position int `json:"position"` Position int `json:"position"`
CategoryID string `json:"categoryID"` CategoryID string `json:"categoryID"`
@ -187,6 +188,8 @@ func (o *Community) MarshalPublicAPIJSON() ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
canView := o.CanView(o.config.MemberIdentity, id)
chat := CommunityChat{ chat := CommunityChat{
ID: id, ID: id,
Name: c.Identity.DisplayName, Name: c.Identity.DisplayName,
@ -196,6 +199,7 @@ func (o *Community) MarshalPublicAPIJSON() ([]byte, error) {
Permissions: c.Permissions, Permissions: c.Permissions,
Members: c.Members, Members: c.Members,
CanPost: canPost, CanPost: canPost,
CanView: canView,
ViewersCanPostReactions: c.ViewersCanPostReactions, ViewersCanPostReactions: c.ViewersCanPostReactions,
TokenGated: o.channelEncrypted(id), TokenGated: o.channelEncrypted(id),
CategoryID: c.CategoryId, CategoryID: c.CategoryId,
@ -328,6 +332,8 @@ func (o *Community) MarshalJSON() ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
canView := o.CanView(o.config.MemberIdentity, id)
chat := CommunityChat{ chat := CommunityChat{
ID: id, ID: id,
Name: c.Identity.DisplayName, Name: c.Identity.DisplayName,
@ -337,6 +343,7 @@ func (o *Community) MarshalJSON() ([]byte, error) {
Permissions: c.Permissions, Permissions: c.Permissions,
Members: c.Members, Members: c.Members,
CanPost: canPost, CanPost: canPost,
CanView: canView,
ViewersCanPostReactions: c.ViewersCanPostReactions, ViewersCanPostReactions: c.ViewersCanPostReactions,
TokenGated: o.channelEncrypted(id), TokenGated: o.channelEncrypted(id),
CategoryID: c.CategoryId, CategoryID: c.CategoryId,
@ -1877,63 +1884,70 @@ func (o *Community) VerifyGrantSignature(data []byte) (*protobuf.Grant, error) {
return grant, nil return grant, nil
} }
func (o *Community) CanPost(pk *ecdsa.PublicKey, chatID string, messageType protobuf.ApplicationMetadataMessage_Type) (bool, error) { func (o *Community) CanView(pk *ecdsa.PublicKey, chatID string) bool {
if o.config.CommunityDescription.Chats == nil { if o.config.CommunityDescription.Chats == nil {
o.config.Logger.Debug("Community.CanPost: no-chats") o.config.Logger.Debug("Community.CanView: no-chats")
return false, nil return false
} }
chat, ok := o.config.CommunityDescription.Chats[chatID] chat, ok := o.config.CommunityDescription.Chats[chatID]
if !ok { if !ok {
o.config.Logger.Debug("Community.CanPost: no chat with id", zap.String("chat-id", chatID)) o.config.Logger.Debug("Community.CanView: no chat with id", zap.String("chat-id", chatID))
return false, nil return false
} }
// community creator can always post, return immediately // community creator can always post, return immediately
if common.IsPubKeyEqual(pk, o.ControlNode()) { if common.IsPubKeyEqual(pk, o.ControlNode()) {
return true, nil return true
} }
if o.isBanned(pk) { if o.isBanned(pk) {
o.config.Logger.Debug("Community.CanPost: user is banned", zap.String("chat-id", chatID)) o.config.Logger.Debug("Community.CanView: user is banned", zap.String("chat-id", chatID))
return false, nil return false
} }
if o.config.CommunityDescription.Members == nil { if o.config.CommunityDescription.Members == nil {
o.config.Logger.Debug("Community.CanPost: no members in org", zap.String("chat-id", chatID)) o.config.Logger.Debug("Community.CanView: no members in org", zap.String("chat-id", chatID))
return false, nil return false
} }
// If community member, also check chat membership next // If community member, also check chat membership next
_, ok = o.config.CommunityDescription.Members[common.PubkeyToHex(pk)] _, ok = o.config.CommunityDescription.Members[common.PubkeyToHex(pk)]
if !ok { if !ok {
o.config.Logger.Debug("Community.CanPost: not a community member", zap.String("chat-id", chatID)) o.config.Logger.Debug("Community.CanView: not a community member", zap.String("chat-id", chatID))
return false, nil return false
} }
if chat.Members == nil { if chat.Members == nil {
o.config.Logger.Debug("Community.CanPost: no members in chat", zap.String("chat-id", chatID)) o.config.Logger.Debug("Community.CanView: no members in chat", zap.String("chat-id", chatID))
return false
}
_, isChatMember := chat.Members[common.PubkeyToHex(pk)]
return isChatMember
}
func (o *Community) CanPost(pk *ecdsa.PublicKey, chatID string, messageType protobuf.ApplicationMetadataMessage_Type) (bool, error) {
hasAccessToChat := o.CanView(pk, chatID)
if !hasAccessToChat {
return false, nil return false, nil
} }
member, isChatMember := chat.Members[common.PubkeyToHex(pk)] chat := o.config.CommunityDescription.Chats[chatID]
member := chat.Members[common.PubkeyToHex(pk)]
switch messageType { switch messageType {
case protobuf.ApplicationMetadataMessage_PIN_MESSAGE: case protobuf.ApplicationMetadataMessage_PIN_MESSAGE:
pinAllowed := o.IsPrivilegedMember(pk) || o.AllowsAllMembersToPinMessage() pinAllowed := o.IsPrivilegedMember(pk) || o.AllowsAllMembersToPinMessage()
return isChatMember && pinAllowed, nil return pinAllowed, nil
case protobuf.ApplicationMetadataMessage_EMOJI_REACTION: case protobuf.ApplicationMetadataMessage_EMOJI_REACTION:
if !isChatMember {
return false, nil
}
isPoster := member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_POSTER isPoster := member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_POSTER
isViewer := member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_VIEWER isViewer := member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_VIEWER
return isPoster || (isViewer && chat.ViewersCanPostReactions), nil return isPoster || (isViewer && chat.ViewersCanPostReactions), nil
default: default:
return isChatMember, nil return member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_POSTER, nil
} }
} }

View File

@ -451,6 +451,44 @@ func (s *CommunitySuite) TestValidateRequestToJoin() {
} }
} }
func (s *CommunitySuite) TestCanPostCanView() {
chatID := "chat-id"
memberKey := common.PubkeyToHex(&s.member1.PublicKey)
// Member has no channel role
description := &protobuf.CommunityDescription{
Members: map[string]*protobuf.CommunityMember{
memberKey: &protobuf.CommunityMember{},
},
Chats: map[string]*protobuf.CommunityChat{
chatID: &protobuf.CommunityChat{
Members: map[string]*protobuf.CommunityMember{
memberKey: &protobuf.CommunityMember{},
},
},
},
}
community := &Community{config: &Config{ID: &s.member2.PublicKey}}
community.config.CommunityDescription = description
result, err := community.CanPost(&s.member1.PublicKey, chatID, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
s.Require().NoError(err)
s.Require().True(result)
result = community.CanView(&s.member1.PublicKey, chatID)
s.Require().True(result)
// member has view channel permissions
description.Chats[chatID].Members[memberKey].ChannelRole = protobuf.CommunityMember_CHANNEL_ROLE_VIEWER
result, err = community.CanPost(&s.member1.PublicKey, chatID, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
s.Require().NoError(err)
s.Require().False(result)
result = community.CanView(&s.member1.PublicKey, chatID)
s.Require().True(result)
}
func (s *CommunitySuite) TestCanPost() { func (s *CommunitySuite) TestCanPost() {
notMember := &s.member3.PublicKey notMember := &s.member3.PublicKey
member := &s.member1.PublicKey member := &s.member1.PublicKey

View File

@ -1006,7 +1006,7 @@ func (m *Manager) ReevaluateMembers(community *Community) (map[protobuf.Communit
if isNewRoleAdmin { if isNewRoleAdmin {
if !isCurrentRoleAdmin { if !isCurrentRoleAdmin {
newPrivilegedRoles[protobuf.CommunityMember_ROLE_ADMIN] = newPrivilegedRoles[protobuf.CommunityMember_ROLE_ADMIN] =
append(newPrivilegedRoles[protobuf.CommunityMember_ROLE_TOKEN_MASTER], memberPubKey) append(newPrivilegedRoles[protobuf.CommunityMember_ROLE_ADMIN], memberPubKey)
} }
// Skip further validation if user has Admin permissions // Skip further validation if user has Admin permissions
continue continue

View File

@ -1361,6 +1361,25 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) TestMemberRoleGetUpdatedWhen
err = <-waitOnChannelKeyToBeDistributedToBob err = <-waitOnChannelKeyToBeDistributedToBob
s.Require().NoError(err) s.Require().NoError(err)
// wait until bob permissions are upgraded
_, err = WaitOnMessengerResponse(
s.bob,
func(r *MessengerResponse) bool {
community, err = s.bob.communitiesManager.GetByID(community.ID())
s.Require().NoError(err)
chats := community.Chats()
if len(chats) == 0 {
return false
}
if chats[chat.ID] == nil {
return false
}
members = chats[chat.ID].Members
return len(members) == 2 && members[s.bob.myHexIdentity()] != nil && members[s.bob.myHexIdentity()].ChannelRole == protobuf.CommunityMember_CHANNEL_ROLE_POSTER
},
"bob never got post permissions",
)
msg = s.sendChatMessage(s.bob, chat.ID, "hello on closed channel from Bob") msg = s.sendChatMessage(s.bob, chat.ID, "hello on closed channel from Bob")
// owner can read the message // owner can read the message