fix: owner without community private key and token master was not able send all admin events (#3819)

This commit is contained in:
Mykhailo Prakhov 2023-07-28 20:18:27 +02:00 committed by GitHub
parent bb942f6c8f
commit 89253ac684
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 85 additions and 47 deletions

View File

@ -813,7 +813,7 @@ func (o *Community) RemoveUserFromOrg(pk *ecdsa.PublicKey) (*protobuf.CommunityD
return nil, ErrNotAdmin
}
if allowedToSendEvents && o.IsMemberOwnerOrAdmin(pk) {
if !isControlNode && o.IsPrivilegedMember(pk) {
return nil, ErrCannotRemoveOwnerOrAdmin
}
@ -883,7 +883,7 @@ func (o *Community) BanUserFromCommunity(pk *ecdsa.PublicKey) (*protobuf.Communi
return nil, ErrNotAdmin
}
if allowedToSendEvents && o.IsMemberOwnerOrAdmin(pk) {
if !isControlNode && o.IsPrivilegedMember(pk) {
return nil, ErrCannotBanOwnerOrAdmin
}
@ -1151,6 +1151,17 @@ func (o *Community) IsOwnerWithoutCommunityKey() bool {
return o.config.PrivateKey == nil && o.IsMemberOwner(o.config.MemberIdentity)
}
func (o *Community) GetPrivilegedMembers() []*ecdsa.PublicKey {
privilegedMembers := make([]*ecdsa.PublicKey, 0)
members := o.GetMemberPubkeys()
for _, member := range members {
if o.IsPrivilegedMember(member) {
privilegedMembers = append(privilegedMembers, member)
}
}
return privilegedMembers
}
func (o *Community) HasPermissionToSendCommunityEvents() bool {
return !o.IsControlNode() && o.hasPermission(o.config.MemberIdentity, manageCommunityRolePermissions())
}
@ -1159,11 +1170,15 @@ func (o *Community) IsMemberOwner(publicKey *ecdsa.PublicKey) bool {
return o.hasPermission(publicKey, ownerRolePermission())
}
func (o *Community) IsMemberTokenMaster(publicKey *ecdsa.PublicKey) bool {
return o.hasPermission(publicKey, tokenMasterRolePermissions())
}
func (o *Community) IsMemberAdmin(publicKey *ecdsa.PublicKey) bool {
return o.hasPermission(publicKey, adminRolePermissions())
}
func (o *Community) IsMemberOwnerOrAdmin(publicKey *ecdsa.PublicKey) bool {
func (o *Community) IsPrivilegedMember(publicKey *ecdsa.PublicKey) bool {
return o.hasPermission(publicKey, manageCommunityRolePermissions())
}
@ -1193,6 +1208,12 @@ func adminRolePermissions() map[protobuf.CommunityMember_Roles]bool {
return roles
}
func tokenMasterRolePermissions() map[protobuf.CommunityMember_Roles]bool {
roles := make(map[protobuf.CommunityMember_Roles]bool)
roles[protobuf.CommunityMember_ROLE_TOKEN_MASTER] = true
return roles
}
func (o *Community) MemberRole(pubKey *ecdsa.PublicKey) protobuf.CommunityMember_Roles {
if o.IsMemberOwner(pubKey) {
return protobuf.CommunityMember_ROLE_OWNER
@ -1213,17 +1234,6 @@ func canDeleteMessageForEveryonePermissions() map[protobuf.CommunityMember_Roles
return roles
}
func (o *Community) GetMemberAdmins() []*ecdsa.PublicKey {
admins := make([]*ecdsa.PublicKey, 0)
members := o.GetMemberPubkeys()
for _, member := range members {
if o.IsMemberAdmin(member) {
admins = append(admins, member)
}
}
return admins
}
func (o *Community) validateRequestToJoinWithChatID(request *protobuf.CommunityRequestToJoin) error {
chat, ok := o.config.CommunityDescription.Chats[request.ChatId]

View File

@ -341,8 +341,8 @@ func (o *Community) updateCommunityDescriptionByCommunityEvent(communityEvent Co
return err
}
if o.IsMemberOwnerOrAdmin(pk) {
return errors.New("attempt to kick an owner or admin of the community from the admin side")
if !o.IsControlNode() && o.IsPrivilegedMember(pk) {
return errors.New("attempt to kick an control node or privileged user from non-control node side")
}
o.removeMemberFromOrg(pk)
@ -353,8 +353,8 @@ func (o *Community) updateCommunityDescriptionByCommunityEvent(communityEvent Co
return err
}
if o.IsMemberOwnerOrAdmin(pk) {
return errors.New("attempt to ban an owner or admin of the community from the admin side")
if !o.IsControlNode() && o.IsPrivilegedMember(pk) {
return errors.New("attempt to ban an control node or privileged user from non-control node side")
}
o.banUserFromCommunity(pk)
@ -429,6 +429,10 @@ func validateAndGetEventsMessageCommunityDescription(signedDescription []byte, s
return nil, err
}
if signer == nil {
return nil, errors.New("CommunityDescription does not contain the control node signature")
}
if !signer.Equal(signerPubkey) {
return nil, errors.New("CommunityDescription was not signed by an owner")
}

View File

@ -1327,8 +1327,8 @@ func (m *Manager) HandleCommunityEventsMessage(signer *ecdsa.PublicKey, message
return nil, ErrOrgNotFound
}
if !community.IsMemberAdmin(signer) {
return nil, errors.New("user is not an admin")
if !community.IsPrivilegedMember(signer) {
return nil, errors.New("user has not permissions to send events")
}
changes, err := community.UpdateCommunityByEvents(adminMessage)
@ -2411,13 +2411,13 @@ func (m *Manager) HandleCommunityRequestToJoinResponse(signer *ecdsa.PublicKey,
return nil, err
}
isOwnerOrAdminSigner := community.IsMemberOwnerOrAdmin(signer)
isPrivilegedUserSigner := community.IsPrivilegedMember(signer)
isControlNodeSigner := common.IsPubKeyEqual(community.PublicKey(), signer)
if !isControlNodeSigner && !isOwnerOrAdminSigner {
if !isControlNodeSigner && !isPrivilegedUserSigner {
return nil, ErrNotAuthorized
}
_, err = community.UpdateCommunityDescription(request.Community, appMetadataMsg, isOwnerOrAdminSigner && !isControlNodeSigner)
_, err = community.UpdateCommunityDescription(request.Community, appMetadataMsg, isPrivilegedUserSigner && !isControlNodeSigner)
if err != nil {
return nil, err
}

View File

@ -244,7 +244,7 @@ func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerBanOwnerWithoutC
testOwnerBanTheSameRole(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestAdminBanControlNode() {
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerBanControlNode() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testOwnerBanControlNode(s, community)
}

View File

@ -91,8 +91,8 @@ func setUpCommunityAndRoles(base CommunityEventsTestsInterface, role protobuf.Co
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
joinCommunity(suite, community, base.GetControlNode(), base.GetEventSender(), request)
refreshMessengerResponses(base)
joinCommunity(suite, community, base.GetControlNode(), base.GetMember(), request)
refreshMessengerResponses(base)
// grant permissions to the event sender
@ -344,14 +344,14 @@ func setUpOnRequestCommunityAndRoles(base CommunityEventsTestsInterface, role pr
// control node creates a community and chat
community := createTestCommunity(base, protobuf.CommunityPermissions_ON_REQUEST)
refreshMessengerResponses(base)
advertiseCommunityTo(s, community, base.GetControlNode(), base.GetEventSender())
advertiseCommunityTo(s, community, base.GetControlNode(), base.GetMember())
refreshMessengerResponses(base)
joinOnRequestCommunity(s, community, base.GetControlNode(), base.GetEventSender())
refreshMessengerResponses(base)
joinOnRequestCommunity(s, community, base.GetControlNode(), base.GetMember())
refreshMessengerResponses(base)
// grant permissions to event sender

View File

@ -246,9 +246,20 @@ func joinOnRequestCommunity(s *suite.Suite, community *communities.Community, co
"user did not receive request to join response",
)
s.Require().NoError(err)
userCommunity, err := user.GetCommunityByID(community.ID())
s.Require().NoError(err)
s.Require().True(userCommunity.HasMember(&user.identity.PublicKey))
// We can't identify which owner is a control node, so owner will receive twice request to join event
_, err = WaitOnMessengerResponse(
controlNode,
func(r *MessengerResponse) bool {
return len(r.Communities()) > 0
},
"user did not receive request to join response",
)
s.Require().NoError(err)
}
func sendChatMessage(s *suite.Suite, sender *Messenger, chatID string, text string) *common.Message {
@ -270,7 +281,7 @@ func grantPermission(s *suite.Suite, community *communities.Community, controlNo
responseAddRole, err := controlNode.AddRoleToMember(&requests.AddRoleToMember{
CommunityID: community.ID(),
User: common.PubkeyToHexBytes(target.IdentityPublicKey()),
Role: protobuf.CommunityMember_ROLE_ADMIN,
Role: role,
})
s.Require().NoError(err)
@ -280,14 +291,25 @@ func grantPermission(s *suite.Suite, community *communities.Community, controlNo
}
rCommunities := response.Communities()
s.Require().Len(rCommunities, 1)
s.Require().True(rCommunities[0].IsMemberAdmin(target.IdentityPublicKey()))
switch role {
case protobuf.CommunityMember_ROLE_OWNER:
s.Require().True(rCommunities[0].IsMemberOwner(target.IdentityPublicKey()))
case protobuf.CommunityMember_ROLE_ADMIN:
s.Require().True(rCommunities[0].IsMemberAdmin(target.IdentityPublicKey()))
case protobuf.CommunityMember_ROLE_TOKEN_MASTER:
s.Require().True(rCommunities[0].IsMemberTokenMaster(target.IdentityPublicKey()))
default:
return false
}
return true
}
checkRole(responseAddRole)
s.Require().True(checkRole(responseAddRole))
_, err = WaitOnMessengerResponse(target, func(response *MessengerResponse) bool {
return checkRole(response)
response, err := WaitOnMessengerResponse(target, func(response *MessengerResponse) bool {
return len(response.Communities()) > 0
}, "community description changed message not received")
s.Require().NoError(err)
s.Require().True(checkRole(response))
}

View File

@ -935,12 +935,14 @@ func (m *Messenger) RequestToJoinCommunity(request *requests.RequestToJoinCommun
return nil, err
}
// send request to join also to community admins
communityAdmins := community.GetMemberAdmins()
for _, communityAdmin := range communityAdmins {
_, err := m.sender.SendPrivate(context.Background(), communityAdmin, &rawMessage)
if err != nil {
return nil, err
if !community.AcceptRequestToJoinAutomatically() {
// send request to join also to community privileged members
privilegedMembers := community.GetPrivilegedMembers()
for _, privilegedMember := range privilegedMembers {
_, err := m.sender.SendPrivate(context.Background(), privilegedMember, &rawMessage)
if err != nil {
return nil, err
}
}
}
@ -1068,10 +1070,10 @@ func (m *Messenger) EditSharedAddressesForCommunity(request *requests.EditShared
return nil, err
}
// send edit message also to community admins
communityAdmins := community.GetMemberAdmins()
for _, communityAdmin := range communityAdmins {
_, err := m.sender.SendPrivate(context.Background(), communityAdmin, &rawMessage)
// send edit message also to privileged members
privilegedMembers := community.GetPrivilegedMembers()
for _, privilegedMember := range privilegedMembers {
_, err := m.sender.SendPrivate(context.Background(), privilegedMember, &rawMessage)
if err != nil {
return nil, err
}

View File

@ -2589,10 +2589,10 @@ func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity) (*Chat, error)
return nil, err
}
isMemberOwnerOrAdmin := community.IsMemberOwnerOrAdmin(chatEntity.GetSigPubKey())
hasPermission := community.IsPrivilegedMember(chatEntity.GetSigPubKey())
pinMessageAllowed := community.AllowsAllMembersToPinMessage()
if (pinMessage && !isMemberOwnerOrAdmin && !pinMessageAllowed) || (!emojiReaction && !canPost) {
if (pinMessage && !hasPermission && !pinMessageAllowed) || (!emojiReaction && !canPost) {
return nil, errors.New("user can't post")
}

View File

@ -36,10 +36,10 @@ func (m *Messenger) sendPinMessage(ctx context.Context, message *common.PinMessa
if err != nil {
return nil, err
}
isMemberOwnerOrAdmin := community.IsMemberOwnerOrAdmin(&m.identity.PublicKey)
hasPermission := community.IsPrivilegedMember(&m.identity.PublicKey)
pinMessageAllowed := community.AllowsAllMembersToPinMessage()
if !pinMessageAllowed && !isMemberOwnerOrAdmin {
if !pinMessageAllowed && !hasPermission {
return nil, errors.New("member can't pin message")
}
}