chore: make the owner without the community private key behave like a… (#3788)

* chore: make the owner without the community private key behave like an admin
* Add test for the owner without community key
* chore: refactor Community fn names related to the roles
This commit is contained in:
Mykhailo Prakhov 2023-07-26 14:16:50 +02:00 committed by GitHub
parent fa46f23f7e
commit c77878bbfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1709 additions and 1427 deletions

View File

@ -507,14 +507,14 @@ func (o *Community) CreateChat(chatID string, chat *protobuf.CommunityChat) (*Co
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToCreateChannelCommunityEvent(chatID, chat))
if err != nil {
return nil, err
@ -526,7 +526,7 @@ func (o *Community) CreateChat(chatID string, chat *protobuf.CommunityChat) (*Co
return nil, err
}
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -539,14 +539,14 @@ func (o *Community) EditChat(chatID string, chat *protobuf.CommunityChat) (*Comm
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToEditChannelCommunityEvent(chatID, chat))
if err != nil {
return nil, err
@ -558,7 +558,7 @@ func (o *Community) EditChat(chatID string, chat *protobuf.CommunityChat) (*Comm
return nil, err
}
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -574,14 +574,14 @@ func (o *Community) DeleteChat(chatID string) (*CommunityChanges, error) {
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToDeleteChannelCommunityEvent(chatID))
if err != nil {
return nil, err
@ -590,7 +590,7 @@ func (o *Community) DeleteChat(chatID string) (*CommunityChanges, error) {
changes := o.deleteChat(chatID)
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -798,18 +798,18 @@ func (o *Community) RemoveUserFromOrg(pk *ecdsa.PublicKey) (*protobuf.CommunityD
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if o.IsAdmin() && o.IsMemberOwnerOrAdmin(pk) {
if allowedToSendEvents && o.IsMemberOwnerOrAdmin(pk) {
return nil, ErrCannotRemoveOwnerOrAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToKickCommunityMemberCommunityEvent(common.PubkeyToHex(pk)))
if err != nil {
return nil, err
@ -818,7 +818,7 @@ func (o *Community) RemoveUserFromOrg(pk *ecdsa.PublicKey) (*protobuf.CommunityD
o.removeMemberFromOrg(pk)
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -841,14 +841,14 @@ func (o *Community) UnbanUserFromCommunity(pk *ecdsa.PublicKey) (*protobuf.Commu
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToUnbanCommunityMemberCommunityEvent(common.PubkeyToHex(pk)))
if err != nil {
return nil, err
@ -857,7 +857,7 @@ func (o *Community) UnbanUserFromCommunity(pk *ecdsa.PublicKey) (*protobuf.Commu
o.unbanUserFromCommunity(pk)
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -868,18 +868,18 @@ func (o *Community) BanUserFromCommunity(pk *ecdsa.PublicKey) (*protobuf.Communi
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if o.IsAdmin() && o.IsMemberOwnerOrAdmin(pk) {
if allowedToSendEvents && o.IsMemberOwnerOrAdmin(pk) {
return nil, ErrCannotBanOwnerOrAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToBanCommunityMemberCommunityEvent(common.PubkeyToHex(pk)))
if err != nil {
return nil, err
@ -888,7 +888,7 @@ func (o *Community) BanUserFromCommunity(pk *ecdsa.PublicKey) (*protobuf.Communi
o.banUserFromCommunity(pk)
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -1076,7 +1076,7 @@ func (o *Community) ValidateRequestToJoin(signer *ecdsa.PublicKey, request *prot
defer o.mutex.Unlock()
// If we are not admin, fuggetaboutit
if !o.IsOwnerOrAdmin() {
if !o.IsControlNode() && !o.HasPermissionToSendCommunityEvents() {
return ErrNotAdmin
}
@ -1103,7 +1103,7 @@ func (o *Community) ValidateEditSharedAddresses(signer *ecdsa.PublicKey, request
defer o.mutex.Unlock()
// If we are not owner, fuggetaboutit
if !o.IsOwner() {
if !o.IsControlNode() {
return ErrNotOwner
}
@ -1118,20 +1118,17 @@ func (o *Community) ValidateEditSharedAddresses(signer *ecdsa.PublicKey, request
return nil
}
func (o *Community) IsOwner() bool {
return o.IsMemberOwner(o.config.MemberIdentity) || o.IsControlNode()
}
// We treat control node as an owner with community key
func (o *Community) IsControlNode() bool {
return o.config.PrivateKey != nil
}
func (o *Community) IsAdmin() bool {
return o.IsMemberAdmin(o.config.MemberIdentity)
func (o *Community) IsOwnerWithoutCommunityKey() bool {
return o.config.PrivateKey == nil && o.IsMemberOwner(o.config.MemberIdentity)
}
func (o *Community) IsOwnerOrAdmin() bool {
return o.IsOwner() || o.IsAdmin()
func (o *Community) HasPermissionToSendCommunityEvents() bool {
return !o.IsControlNode() && o.hasPermission(o.config.MemberIdentity, manageCommunityRolePermissions())
}
func (o *Community) IsMemberOwner(publicKey *ecdsa.PublicKey) bool {
@ -1143,11 +1140,18 @@ func (o *Community) IsMemberAdmin(publicKey *ecdsa.PublicKey) bool {
}
func (o *Community) IsMemberOwnerOrAdmin(publicKey *ecdsa.PublicKey) bool {
return o.hasPermission(publicKey, ownerOrAdminRolePermissions())
return o.hasPermission(publicKey, manageCommunityRolePermissions())
}
func manageCommunityRolePermissions() map[protobuf.CommunityMember_Roles]bool {
roles := make(map[protobuf.CommunityMember_Roles]bool)
roles[protobuf.CommunityMember_ROLE_OWNER] = true
roles[protobuf.CommunityMember_ROLE_ADMIN] = true
return roles
}
func canManageUsersRolePermissions() map[protobuf.CommunityMember_Roles]bool {
roles := ownerOrAdminRolePermissions()
roles := manageCommunityRolePermissions()
roles[protobuf.CommunityMember_ROLE_MANAGE_USERS] = true
return roles
}
@ -1164,13 +1168,6 @@ func adminRolePermissions() map[protobuf.CommunityMember_Roles]bool {
return roles
}
func ownerOrAdminRolePermissions() map[protobuf.CommunityMember_Roles]bool {
roles := make(map[protobuf.CommunityMember_Roles]bool)
roles[protobuf.CommunityMember_ROLE_OWNER] = true
roles[protobuf.CommunityMember_ROLE_ADMIN] = true
return roles
}
func (o *Community) MemberRole(pubKey *ecdsa.PublicKey) protobuf.CommunityMember_Roles {
if o.IsMemberOwner(pubKey) {
return protobuf.CommunityMember_ROLE_OWNER
@ -1186,7 +1183,7 @@ func (o *Community) MemberRole(pubKey *ecdsa.PublicKey) protobuf.CommunityMember
}
func canDeleteMessageForEveryonePermissions() map[protobuf.CommunityMember_Roles]bool {
roles := ownerOrAdminRolePermissions()
roles := manageCommunityRolePermissions()
roles[protobuf.CommunityMember_ROLE_MODERATE_CONTENT] = true
return roles
}
@ -1312,7 +1309,7 @@ func (o *Community) toBytes() ([]byte, error) {
}
// If we are not a control node, use the received serialized version
if !o.IsOwner() {
if !o.IsControlNode() {
return o.config.MarshaledCommunityDescription, nil
}
@ -1436,10 +1433,10 @@ func (o *Community) AddTokenPermission(permission *protobuf.CommunityTokenPermis
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin || (isAdmin && permission.Type == protobuf.CommunityTokenPermission_BECOME_ADMIN) {
if !isControlNode && !allowedToSendEvents || (allowedToSendEvents && permission.Type == protobuf.CommunityTokenPermission_BECOME_ADMIN) {
return nil, ErrNotEnoughPermissions
}
@ -1448,14 +1445,14 @@ func (o *Community) AddTokenPermission(permission *protobuf.CommunityTokenPermis
return nil, err
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToCommunityTokenPermissionChangeCommunityEvent(permission))
if err != nil {
return nil, err
}
}
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -1466,10 +1463,10 @@ func (o *Community) UpdateTokenPermission(permissionID string, tokenPermission *
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin || (isAdmin && tokenPermission.Type == protobuf.CommunityTokenPermission_BECOME_ADMIN) {
if !isControlNode && !allowedToSendEvents || (allowedToSendEvents && tokenPermission.Type == protobuf.CommunityTokenPermission_BECOME_ADMIN) {
return nil, ErrNotEnoughPermissions
}
@ -1478,14 +1475,14 @@ func (o *Community) UpdateTokenPermission(permissionID string, tokenPermission *
return nil, err
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToCommunityTokenPermissionChangeCommunityEvent(tokenPermission))
if err != nil {
return nil, err
}
}
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -1502,10 +1499,10 @@ func (o *Community) DeleteTokenPermission(permissionID string) (*CommunityChange
return nil, ErrTokenPermissionNotFound
}
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin || (isAdmin && permission.Type == protobuf.CommunityTokenPermission_BECOME_ADMIN) {
if !isControlNode && !allowedToSendEvents || (allowedToSendEvents && permission.Type == protobuf.CommunityTokenPermission_BECOME_ADMIN) {
return nil, ErrNotEnoughPermissions
}
@ -1514,14 +1511,14 @@ func (o *Community) DeleteTokenPermission(permissionID string) (*CommunityChange
return nil, err
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToCommunityTokenPermissionDeleteCommunityEvent(permission))
if err != nil {
return nil, err
}
}
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -1720,7 +1717,7 @@ func (o *Community) CanManageUsers(pk *ecdsa.PublicKey) bool {
o.mutex.Lock()
defer o.mutex.Unlock()
if o.IsOwner() {
if o.IsControlNode() {
return true
}
@ -1737,7 +1734,7 @@ func (o *Community) CanDeleteMessageForEveryone(pk *ecdsa.PublicKey) bool {
o.mutex.Lock()
defer o.mutex.Unlock()
if o.IsOwner() {
if o.IsControlNode() {
return true
}
@ -1763,7 +1760,7 @@ func (o *Community) canJoin() bool {
return false
}
if o.IsOwner() {
if o.IsControlNode() {
return true
}
@ -1808,7 +1805,7 @@ func (o *Community) RequestsToJoin() []*RequestToJoin {
}
func (o *Community) AddMember(publicKey *ecdsa.PublicKey, roles []protobuf.CommunityMember_Roles) (*CommunityChanges, error) {
if !o.IsOwnerOrAdmin() {
if !o.IsControlNode() && !o.HasPermissionToSendCommunityEvents() {
return nil, ErrNotAdmin
}
@ -1832,7 +1829,7 @@ func (o *Community) AddMemberToChat(chatID string, publicKey *ecdsa.PublicKey, r
o.mutex.Lock()
defer o.mutex.Unlock()
if !o.IsOwnerOrAdmin() {
if !o.IsControlNode() && !o.HasPermissionToSendCommunityEvents() {
return nil, ErrNotAuthorized
}
@ -1875,7 +1872,7 @@ func (o *Community) AddMemberRevealedAccounts(memberID string, accounts []*proto
o.mutex.Lock()
defer o.mutex.Unlock()
if !o.IsOwnerOrAdmin() {
if !o.IsControlNode() && !o.HasPermissionToSendCommunityEvents() {
return nil, ErrNotAdmin
}
@ -1896,16 +1893,16 @@ func (o *Community) AddMemberWithRevealedAccounts(dbRequest *RequestToJoin, role
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
changes := o.addMemberWithRevealedAccounts(dbRequest.PublicKey, roles, accounts, dbRequest.Clock)
if isAdmin {
if allowedToSendEvents {
acceptedRequestsToJoin := make(map[string]*protobuf.CommunityRequestToJoin)
acceptedRequestsToJoin[dbRequest.PublicKey] = dbRequest.ToCommunityRequestToJoinProtobuf()
@ -1919,7 +1916,7 @@ func (o *Community) AddMemberWithRevealedAccounts(dbRequest *RequestToJoin, role
}
}
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -2171,14 +2168,14 @@ func (o *Community) DeclineRequestToJoin(dbRequest *RequestToJoin) error {
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return ErrNotAdmin
}
if isAdmin {
if allowedToSendEvents {
rejectedRequestsToJoin := make(map[string]*protobuf.CommunityRequestToJoin)
rejectedRequestsToJoin[dbRequest.PublicKey] = dbRequest.ToCommunityRequestToJoinProtobuf()
@ -2192,7 +2189,7 @@ func (o *Community) DeclineRequestToJoin(dbRequest *RequestToJoin) error {
}
}
if isOwner {
if isControlNode {
// typically, community's clock is increased implicitly when making changes
// to it, however in this scenario there are no changes in the community, yet
// we need to increase the clock to ensure the owner event is processed by other

View File

@ -40,14 +40,14 @@ func (o *Community) CreateCategory(categoryID string, categoryName string, chatI
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToCreateCategoryCommunityEvent(categoryID, categoryName, chatIDs))
if err != nil {
return nil, err
@ -59,7 +59,7 @@ func (o *Community) CreateCategory(categoryID string, categoryName string, chatI
return nil, err
}
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -80,14 +80,14 @@ func (o *Community) EditCategory(categoryID string, categoryName string, chatIDs
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToEditCategoryCommunityEvent(categoryID, categoryName, chatIDs))
if err != nil {
return nil, err
@ -100,7 +100,7 @@ func (o *Community) EditCategory(categoryID string, categoryName string, chatIDs
return nil, err
}
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -121,14 +121,14 @@ func (o *Community) ReorderCategories(categoryID string, newPosition int) (*Comm
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToReorderCategoryCommunityEvent(categoryID, newPosition))
if err != nil {
return nil, err
@ -140,7 +140,7 @@ func (o *Community) ReorderCategories(categoryID string, newPosition int) (*Comm
return nil, err
}
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -161,14 +161,14 @@ func (o *Community) ReorderChat(categoryID string, chatID string, newPosition in
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToReorderChannelCommunityEvent(categoryID, chatID, newPosition))
if err != nil {
return nil, err
@ -180,7 +180,7 @@ func (o *Community) ReorderChat(categoryID string, chatID string, newPosition in
return nil, err
}
if isOwner {
if isControlNode {
o.increaseClock()
}
@ -316,14 +316,14 @@ func (o *Community) DeleteCategory(categoryID string) (*CommunityChanges, error)
o.mutex.Lock()
defer o.mutex.Unlock()
isOwner := o.IsOwner()
isAdmin := o.IsAdmin()
isControlNode := o.IsControlNode()
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotAdmin
}
if isAdmin {
if allowedToSendEvents {
err := o.addNewCommunityEvent(o.ToDeleteCategoryCommunityEvent(categoryID))
if err != nil {
return nil, err
@ -335,7 +335,7 @@ func (o *Community) DeleteCategory(categoryID string) (*CommunityChanges, error)
return nil, err
}
if isOwner {
if isControlNode {
o.increaseClock()
}

View File

@ -787,10 +787,10 @@ func (m *Manager) EditCommunity(request *requests.EditCommunity) (*Community, er
return nil, ErrOrgNotFound
}
isOwner := community.IsOwner()
isAdmin := community.IsAdmin()
isControlNode := community.IsControlNode()
allowedToSendEvents := community.HasPermissionToSendCommunityEvents()
if !isOwner && !isAdmin {
if !isControlNode && !allowedToSendEvents {
return nil, ErrNotEnoughPermissions
}
@ -823,7 +823,7 @@ func (m *Manager) EditCommunity(request *requests.EditCommunity) (*Community, er
return nil, err
}
if isAdmin {
if allowedToSendEvents {
err := community.addNewCommunityEvent(community.ToCommunityEditCommunityEvent(newDescription))
if err != nil {
return nil, err
@ -836,7 +836,7 @@ func (m *Manager) EditCommunity(request *requests.EditCommunity) (*Community, er
return nil, err
}
if isOwner {
if isControlNode {
community.increaseClock()
}
@ -1300,9 +1300,9 @@ func (m *Manager) HandleCommunityEventsMessage(signer *ecdsa.PublicKey, message
return nil, err
}
// Owner cerifies admins events and publish changes
// all other users only apply changes to the community
if changes.Community.IsOwner() {
// Control node cerifies community events and publish changes
// all other nodes only apply changes to the community
if changes.Community.IsControlNode() {
changes.Community.increaseClock()
err = m.persistence.SaveCommunity(changes.Community)
if err != nil {
@ -1798,7 +1798,7 @@ func (m *Manager) HandleCommunityEditSharedAddresses(signer *ecdsa.PublicKey, re
return err
}
if community.IsOwner() {
if community.IsControlNode() {
m.publish(&Subscription{Community: community})
}
@ -2331,13 +2331,13 @@ func (m *Manager) HandleCommunityRequestToJoinResponse(signer *ecdsa.PublicKey,
return nil, err
}
isAdminSigner := community.IsMemberAdmin(signer)
isOwnerSigner := common.IsPubKeyEqual(community.PublicKey(), signer)
if !isOwnerSigner && !isAdminSigner {
isOwnerOrAdminSigner := community.IsMemberOwnerOrAdmin(signer)
isControlNodeSigner := common.IsPubKeyEqual(community.PublicKey(), signer)
if !isControlNodeSigner && !isOwnerOrAdminSigner {
return nil, ErrNotAuthorized
}
_, err = community.UpdateCommunityDescription(request.Community, appMetadataMsg, isAdminSigner)
_, err = community.UpdateCommunityDescription(request.Community, appMetadataMsg, isOwnerOrAdminSigner && !isControlNodeSigner)
if err != nil {
return nil, err
}
@ -4012,12 +4012,10 @@ func (m *Manager) saveAndPublish(community *Community) error {
return err
}
if community.IsOwner() {
if community.IsControlNode() {
m.publish(&Subscription{Community: community})
return nil
}
if community.IsAdmin() {
} else if community.HasPermissionToSendCommunityEvents() {
err := m.persistence.SaveCommunityEvents(community)
if err != nil {
return err

View File

@ -0,0 +1,280 @@
package protocol
import (
"crypto/ecdsa"
"testing"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/requests"
"github.com/status-im/status-go/protocol/tt"
"github.com/status-im/status-go/waku"
)
func TestOwnerWithoutCommunityKeyCommunityEventsSuite(t *testing.T) {
suite.Run(t, new(OwnerWithoutCommunityKeyCommunityEventsSuite))
}
type OwnerWithoutCommunityKeyCommunityEventsSuite struct {
suite.Suite
controlNode *Messenger
ownerWithoutCommunityKey *Messenger
alice *Messenger
// If one wants to send messages between different instances of Messenger,
// a single Waku service should be shared.
shh types.Waku
logger *zap.Logger
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) GetControlNode() *Messenger {
return s.controlNode
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) GetEventSender() *Messenger {
return s.ownerWithoutCommunityKey
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) GetMember() *Messenger {
return s.alice
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) GetSuite() *suite.Suite {
return &s.Suite
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) SetupTest() {
s.logger = tt.MustCreateTestLogger()
config := waku.DefaultConfig
config.MinimumAcceptedPoW = 0
shh := waku.New(&config, s.logger)
s.shh = gethbridge.NewGethWakuWrapper(shh)
s.Require().NoError(shh.Start())
s.controlNode = s.newMessenger()
s.ownerWithoutCommunityKey = s.newMessenger()
s.alice = s.newMessenger()
_, err := s.controlNode.Start()
s.Require().NoError(err)
_, err = s.ownerWithoutCommunityKey.Start()
s.Require().NoError(err)
_, err = s.alice.Start()
s.Require().NoError(err)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TearDownTest() {
s.Require().NoError(s.controlNode.Shutdown())
s.Require().NoError(s.ownerWithoutCommunityKey.Shutdown())
s.Require().NoError(s.alice.Shutdown())
_ = s.logger.Sync()
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) newMessengerWithKey(shh types.Waku, privateKey *ecdsa.PrivateKey) *Messenger {
messenger, err := newCommunitiesTestMessenger(shh, privateKey, s.logger, nil, nil)
s.Require().NoError(err)
return messenger
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) newMessenger() *Messenger {
privateKey, err := crypto.GenerateKey()
s.Require().NoError(err)
return s.newMessengerWithKey(s.shh, privateKey)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerEditCommunityDescription() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
editCommunityDescription(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCreateEditDeleteChannels() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testCreateEditDeleteChannels(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCreateEditDeleteBecomeMemberPermission() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testCreateEditDeleteBecomeMemberPermission(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCannotCreateBecomeAdminPermission() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
permissionRequest := createTestPermissionRequest(community)
permissionRequest.Type = protobuf.CommunityTokenPermission_BECOME_ADMIN
response, err := s.ownerWithoutCommunityKey.CreateCommunityTokenPermission(permissionRequest)
s.Require().Nil(response)
s.Require().Error(err)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCannotEditBecomeAdminPermission() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
permissionRequest := createTestPermissionRequest(community)
permissionRequest.Type = protobuf.CommunityTokenPermission_BECOME_ADMIN
// control node creates BECOME_ADMIN permission
response, err := s.controlNode.CreateCommunityTokenPermission(permissionRequest)
s.Require().NoError(err)
var tokenPermissionID string
for id := range response.CommunityChanges[0].TokenPermissionsAdded {
tokenPermissionID = id
}
s.Require().NotEqual(tokenPermissionID, "")
ownerCommunity, err := s.controlNode.communitiesManager.GetByID(community.ID())
s.Require().NoError(err)
assertCheckTokenPermissionCreated(&s.Suite, ownerCommunity)
// then, ensure event sender receives updated community
_, err = WaitOnMessengerResponse(
s.ownerWithoutCommunityKey,
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
"event sender did not receive updated community",
)
s.Require().NoError(err)
eventSenderCommunity, err := s.ownerWithoutCommunityKey.communitiesManager.GetByID(community.ID())
s.Require().NoError(err)
assertCheckTokenPermissionCreated(&s.Suite, eventSenderCommunity)
permissionRequest.TokenCriteria[0].Symbol = "UPDATED"
permissionRequest.TokenCriteria[0].Amount = "200"
permissionEditRequest := &requests.EditCommunityTokenPermission{
PermissionID: tokenPermissionID,
CreateCommunityTokenPermission: *permissionRequest,
}
// then, event sender tries to edit permission
response, err = s.ownerWithoutCommunityKey.EditCommunityTokenPermission(permissionEditRequest)
s.Require().Error(err)
s.Require().Nil(response)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCannotDeleteBecomeAdminPermission() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
permissionRequest := createTestPermissionRequest(community)
permissionRequest.Type = protobuf.CommunityTokenPermission_BECOME_ADMIN
// control node creates BECOME_ADMIN permission
response, err := s.controlNode.CreateCommunityTokenPermission(permissionRequest)
s.Require().NoError(err)
var tokenPermissionID string
for id := range response.CommunityChanges[0].TokenPermissionsAdded {
tokenPermissionID = id
}
s.Require().NotEqual(tokenPermissionID, "")
// then, ensure event sender receives updated community
_, err = WaitOnMessengerResponse(
s.ownerWithoutCommunityKey,
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
"event sender did not receive updated community",
)
s.Require().NoError(err)
eventSenderCommunity, err := s.ownerWithoutCommunityKey.communitiesManager.GetByID(community.ID())
s.Require().NoError(err)
assertCheckTokenPermissionCreated(&s.Suite, eventSenderCommunity)
deleteTokenPermission := &requests.DeleteCommunityTokenPermission{
CommunityID: community.ID(),
PermissionID: tokenPermissionID,
}
// then event sender tries to delete BECOME_ADMIN permission which should fail
response, err = s.ownerWithoutCommunityKey.DeleteCommunityTokenPermission(deleteTokenPermission)
s.Require().Error(err)
s.Require().Nil(response)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerAcceptMemberRequestToJoin() {
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
// set up additional user that will send request to join
user := s.newMessenger()
testAcceptMemberRequestToJoin(s, community, user)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRejectMemberRequestToJoin() {
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
// set up additional user that will send request to join
user := s.newMessenger()
testRejectMemberRequestToJoin(s, community, user)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCreateEditDeleteCategories() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testCreateEditDeleteCategories(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerReorderChannelsAndCategories() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testReorderChannelsAndCategories(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerKickOwnerWithoutCommunityKey() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testEventSenderKickTheSameRole(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerKickControlNode() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testEventSenderKickControlNode(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerKickMember() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
kickMember(s, community.ID(), common.PubkeyToHex(&s.alice.identity.PublicKey))
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerBanOwnerWithoutCommunityKey() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testOwnerBanTheSameRole(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestAdminBanControlNode() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testOwnerBanControlNode(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerBanUnbanMember() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testBanUnbanMember(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerDeleteAnyMessageInTheCommunity() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testDeleteAnyMessageInTheCommunity(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerPinMessage() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testEventSenderPinMessage(s, community)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerMintToken() {
setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
// TODO owner test: Mint Tokens (rescticted)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerAirdropTokens() {
setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
// TODO owner test: Airdrop Tokens (restricted)
}
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestMemberReceiveOwnerEventsWhenControlNodeOffline() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
testMemberReceiveEventsWhenControlNodeOffline(s, community)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -204,6 +204,53 @@ func joinCommunity(s *suite.Suite, community *communities.Community, owner *Mess
s.Require().NoError(err)
}
func joinOnRequestCommunity(s *suite.Suite, community *communities.Community, controlNode *Messenger, user *Messenger) {
// Request to join the community
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
response, err := user.RequestToJoinCommunity(request)
s.Require().NoError(err)
s.Require().NotNil(response)
s.Require().Len(response.RequestsToJoinCommunity, 1)
requestToJoin := response.RequestsToJoinCommunity[0]
s.Require().Equal(requestToJoin.PublicKey, common.PubkeyToHex(&user.identity.PublicKey))
response, err = WaitOnMessengerResponse(
controlNode,
func(r *MessengerResponse) bool {
return len(r.RequestsToJoinCommunity) > 0
},
"control node did not receive community request to join",
)
s.Require().NoError(err)
userRequestToJoin := response.RequestsToJoinCommunity[0]
s.Require().Equal(userRequestToJoin.PublicKey, common.PubkeyToHex(&user.identity.PublicKey))
// accept join request
acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: requestToJoin.ID}
response, err = controlNode.AcceptRequestToJoinCommunity(acceptRequestToJoin)
s.Require().NoError(err)
s.Require().NotNil(response)
updatedCommunity := response.Communities()[0]
s.Require().NotNil(updatedCommunity)
s.Require().True(updatedCommunity.HasMember(&user.identity.PublicKey))
// receive request to join response
_, err = WaitOnMessengerResponse(
user,
func(r *MessengerResponse) bool {
return len(r.Communities()) > 0
},
"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))
}
func sendChatMessage(s *suite.Suite, sender *Messenger, chatID string, text string) *common.Message {
msg := &common.Message{
ChatMessage: protobuf.ChatMessage{
@ -218,3 +265,29 @@ func sendChatMessage(s *suite.Suite, sender *Messenger, chatID string, text stri
return msg
}
func grantPermission(s *suite.Suite, community *communities.Community, controlNode *Messenger, target *Messenger, role protobuf.CommunityMember_Roles) {
responseAddRole, err := controlNode.AddRoleToMember(&requests.AddRoleToMember{
CommunityID: community.ID(),
User: common.PubkeyToHexBytes(target.IdentityPublicKey()),
Role: protobuf.CommunityMember_ROLE_ADMIN,
})
s.Require().NoError(err)
checkRole := func(response *MessengerResponse) bool {
if len(response.Communities()) == 0 {
return false
}
rCommunities := response.Communities()
s.Require().Len(rCommunities, 1)
s.Require().True(rCommunities[0].IsMemberAdmin(target.IdentityPublicKey()))
return true
}
checkRole(responseAddRole)
_, err = WaitOnMessengerResponse(target, func(response *MessengerResponse) bool {
return checkRole(response)
}, "community description changed message not received")
s.Require().NoError(err)
}

View File

@ -627,7 +627,6 @@ func (s *MessengerCommunitiesSuite) TestImportCommunity() {
s.Require().Len(response.Communities(), 1)
s.Require().Len(response.CommunitiesSettings(), 1)
s.Require().True(response.Communities()[0].Joined())
s.Require().True(response.Communities()[0].IsOwner())
s.Require().True(response.Communities()[0].IsControlNode())
community := response.Communities()[0]
@ -697,7 +696,7 @@ func (s *MessengerCommunitiesSuite) TestRemovePrivateKey() {
s.Require().Len(response.Communities(), 1)
community := response.Communities()[0]
s.Require().True(community.IsOwner())
s.Require().True(community.IsControlNode())
s.Require().True(community.IsControlNode())
response, err = s.bob.RemovePrivateKey(community.ID())
@ -705,7 +704,7 @@ func (s *MessengerCommunitiesSuite) TestRemovePrivateKey() {
s.Require().Len(response.Communities(), 1)
community = response.Communities()[0]
s.Require().True(community.IsOwner())
s.Require().True(community.IsOwnerWithoutCommunityKey())
s.Require().False(community.IsControlNode())
}
@ -726,7 +725,7 @@ func (s *MessengerCommunitiesSuite) TestRolesAfterImportCommunity() {
s.Require().Len(response.Communities(), 1)
s.Require().Len(response.CommunitiesSettings(), 1)
s.Require().True(response.Communities()[0].Joined())
s.Require().True(response.Communities()[0].IsOwner())
s.Require().True(response.Communities()[0].IsControlNode())
s.Require().True(response.Communities()[0].IsMemberOwner(&s.bob.identity.PublicKey))
s.Require().False(response.Communities()[0].IsMemberOwner(&s.alice.identity.PublicKey))
@ -2520,8 +2519,12 @@ func (s *MessengerCommunitiesSuite) TestSyncCommunity() {
s.Equal(newCommunity.Muted(), tnc.Muted())
s.Equal(newCommunity.Joined(), tnc.Joined())
s.Equal(newCommunity.Spectated(), tnc.Spectated())
s.Equal(newCommunity.IsOwner(), tnc.IsOwner())
s.Equal(newCommunity.InvitationOnly(), tnc.InvitationOnly())
s.True(newCommunity.IsControlNode())
s.False(newCommunity.IsOwnerWithoutCommunityKey())
s.True(tnc.IsOwnerWithoutCommunityKey())
s.False(tnc.IsControlNode())
}
// TestSyncCommunity_RequestToJoin tests more complex pairing and syncing scenario where one paired device

View File

@ -2314,7 +2314,7 @@ func (m *Messenger) updateChatFirstMessageTimestamp(chat *Chat, timestamp uint32
return err
}
if community.IsOwner() && chat.UpdateFirstMessageTimestamp(timestamp) {
if community.IsControlNode() && chat.UpdateFirstMessageTimestamp(timestamp) {
community, changes, err := m.communitiesManager.EditChatFirstMessageTimestamp(community.ID(), chat.ID, chat.FirstMessageTimestamp)
if err != nil {
return err

View File

@ -1682,7 +1682,7 @@ func (m *Messenger) CreateCommunityTokenPermission(request *requests.CreateCommu
return nil, err
}
if community.IsOwner() {
if community.IsControlNode() {
// check existing member permission once, then check periodically
go func() {
err := m.communitiesManager.CheckMemberPermissions(community, true)
@ -1715,7 +1715,7 @@ func (m *Messenger) EditCommunityTokenPermission(request *requests.EditCommunity
// BECOME_MEMBER permissions and kick them if necessary
//
// We do this in a separate routine to not block this function
if community.IsOwner() {
if community.IsControlNode() {
go func() {
err := m.communitiesManager.CheckMemberPermissions(community, true)
if err != nil {
@ -1743,7 +1743,7 @@ func (m *Messenger) DeleteCommunityTokenPermission(request *requests.DeleteCommu
// check if members still fulfill the token criteria
// We do this in a separate routine to not block this function
if community.IsOwner() {
if community.IsControlNode() {
go func() {
becomeAdminPermissions := community.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_ADMIN)