github.com/status-im/status-go@v1.1.0/protocol/communities/community_test.go (about)

     1  package communities
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"encoding/json"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/golang/protobuf/proto"
    10  
    11  	"github.com/stretchr/testify/suite"
    12  
    13  	"github.com/status-im/status-go/eth-node/crypto"
    14  	"github.com/status-im/status-go/protocol/common"
    15  	"github.com/status-im/status-go/protocol/protobuf"
    16  )
    17  
    18  func TestCommunitySuite(t *testing.T) {
    19  	suite.Run(t, new(CommunitySuite))
    20  }
    21  
    22  const testChatID1 = "chat-id-1"
    23  const testCategoryID1 = "category-id-1"
    24  const testCategoryName1 = "category-name-1"
    25  const testChatID2 = "chat-id-2"
    26  
    27  type TimeSourceStub struct {
    28  }
    29  
    30  func (t *TimeSourceStub) GetCurrentTime() uint64 {
    31  	return uint64(time.Now().Unix())
    32  }
    33  
    34  type CommunitySuite struct {
    35  	suite.Suite
    36  
    37  	identity    *ecdsa.PrivateKey
    38  	communityID []byte
    39  
    40  	member1 *ecdsa.PrivateKey
    41  	member2 *ecdsa.PrivateKey
    42  	member3 *ecdsa.PrivateKey
    43  
    44  	member1Key string
    45  	member2Key string
    46  	member3Key string
    47  }
    48  
    49  func (s *CommunitySuite) SetupTest() {
    50  	identity, err := crypto.GenerateKey()
    51  	s.Require().NoError(err)
    52  	s.identity = identity
    53  	s.communityID = crypto.CompressPubkey(&identity.PublicKey)
    54  
    55  	member1, err := crypto.GenerateKey()
    56  	s.Require().NoError(err)
    57  	s.member1 = member1
    58  
    59  	member2, err := crypto.GenerateKey()
    60  	s.Require().NoError(err)
    61  	s.member2 = member2
    62  
    63  	member3, err := crypto.GenerateKey()
    64  	s.Require().NoError(err)
    65  	s.member3 = member3
    66  
    67  	s.member1Key = common.PubkeyToHex(&s.member1.PublicKey)
    68  	s.member2Key = common.PubkeyToHex(&s.member2.PublicKey)
    69  	s.member3Key = common.PubkeyToHex(&s.member3.PublicKey)
    70  
    71  }
    72  
    73  func (s *CommunitySuite) TestHasPermission() {
    74  	// returns false if empty public key is passed
    75  	community := &Community{}
    76  	ownerKey, err := crypto.GenerateKey()
    77  	s.Require().NoError(err)
    78  
    79  	nonMemberKey, err := crypto.GenerateKey()
    80  	s.Require().NoError(err)
    81  
    82  	memberKey, err := crypto.GenerateKey()
    83  	s.Require().NoError(err)
    84  
    85  	s.Require().False(community.hasRoles(nil, adminRole()))
    86  
    87  	// returns false if key is passed, but config is nil
    88  	s.Require().False(community.hasRoles(&nonMemberKey.PublicKey, adminRole()))
    89  
    90  	// returns true if the user is the owner
    91  
    92  	communityDescription := &protobuf.CommunityDescription{}
    93  	communityDescription.Members = make(map[string]*protobuf.CommunityMember)
    94  	communityDescription.Members[common.PubkeyToHex(&ownerKey.PublicKey)] = &protobuf.CommunityMember{Roles: []protobuf.CommunityMember_Roles{protobuf.CommunityMember_ROLE_OWNER}}
    95  	communityDescription.Members[common.PubkeyToHex(&memberKey.PublicKey)] = &protobuf.CommunityMember{Roles: []protobuf.CommunityMember_Roles{protobuf.CommunityMember_ROLE_ADMIN}}
    96  
    97  	community.config = &Config{ID: &ownerKey.PublicKey, CommunityDescription: communityDescription}
    98  
    99  	s.Require().True(community.hasRoles(&ownerKey.PublicKey, ownerRole()))
   100  
   101  	// return false if user is not a member
   102  	s.Require().False(community.hasRoles(&nonMemberKey.PublicKey, adminRole()))
   103  
   104  	// return true if user is a member and has permissions
   105  	s.Require().True(community.hasRoles(&memberKey.PublicKey, adminRole()))
   106  
   107  	// return false if user is a member and does not have permissions
   108  	s.Require().False(community.hasRoles(&memberKey.PublicKey, ownerRole()))
   109  
   110  }
   111  
   112  func (s *CommunitySuite) TestCreateChat() {
   113  	newChatID := "new-chat-id"
   114  	org := s.buildCommunity(&s.identity.PublicKey)
   115  	org.config.PrivateKey = nil
   116  	org.config.ID = nil
   117  
   118  	identity := &protobuf.ChatIdentity{
   119  		DisplayName: "new-chat-display-name",
   120  		Description: "new-chat-description",
   121  	}
   122  	permissions := &protobuf.CommunityPermissions{
   123  		Access: protobuf.CommunityPermissions_AUTO_ACCEPT,
   124  	}
   125  
   126  	_, err := org.CreateChat(newChatID, &protobuf.CommunityChat{
   127  		Identity:    identity,
   128  		Permissions: permissions,
   129  	})
   130  
   131  	s.Require().Equal(ErrNotAuthorized, err)
   132  
   133  	org.config.PrivateKey = s.identity
   134  	org.config.ID = &s.identity.PublicKey
   135  
   136  	changes, err := org.CreateChat(newChatID, &protobuf.CommunityChat{
   137  		Identity:    identity,
   138  		Permissions: permissions,
   139  	})
   140  
   141  	description := org.config.CommunityDescription
   142  
   143  	s.Require().NoError(err)
   144  	s.Require().NotNil(description)
   145  	s.Require().NotNil(description.Chats[newChatID])
   146  	s.Require().NotEmpty(description.Clock)
   147  	s.Require().Equal(len(description.Chats)-1, int(description.Chats[newChatID].Position))
   148  	s.Require().Equal(permissions, description.Chats[newChatID].Permissions)
   149  	s.Require().Equal(identity, description.Chats[newChatID].Identity)
   150  
   151  	s.Require().NotNil(changes)
   152  	s.Require().NotNil(changes.ChatsAdded[newChatID])
   153  
   154  	// Add a community with the same name
   155  
   156  	_, err = org.CreateChat("different-chat-id", &protobuf.CommunityChat{
   157  		Identity:    identity,
   158  		Permissions: permissions,
   159  	})
   160  
   161  	s.Require().Error(err)
   162  }
   163  
   164  func (s *CommunitySuite) TestEditChat() {
   165  	newChatID := "new-chat-id"
   166  	org := s.buildCommunity(&s.identity.PublicKey)
   167  
   168  	identity := &protobuf.ChatIdentity{
   169  		DisplayName: "new-chat-display-name",
   170  		Description: "new-chat-description",
   171  		Emoji:       "😎",
   172  		Color:       "#000000",
   173  	}
   174  	permissions := &protobuf.CommunityPermissions{
   175  		Access:  protobuf.CommunityPermissions_AUTO_ACCEPT,
   176  		Private: false,
   177  	}
   178  
   179  	_, err := org.CreateChat(newChatID, &protobuf.CommunityChat{
   180  		Identity:                identity,
   181  		Permissions:             permissions,
   182  		HideIfPermissionsNotMet: false,
   183  	})
   184  	s.Require().NoError(err)
   185  
   186  	org.config.PrivateKey = nil
   187  	org.config.ID = nil
   188  	editedIdentity := &protobuf.ChatIdentity{
   189  		DisplayName: "edited-new-chat-display-name",
   190  		Description: "edited-new-chat-description",
   191  		Emoji:       "🤘",
   192  		Color:       "#FFFFFF",
   193  	}
   194  	editedPermissions := &protobuf.CommunityPermissions{
   195  		Access:  protobuf.CommunityPermissions_AUTO_ACCEPT,
   196  		Private: true,
   197  	}
   198  	_, err = org.EditChat(newChatID, &protobuf.CommunityChat{
   199  		Identity:    editedIdentity,
   200  		Permissions: editedPermissions,
   201  	})
   202  	s.Require().Equal(ErrNotAuthorized, err)
   203  
   204  	description := org.config.CommunityDescription
   205  	org.config.PrivateKey = s.identity
   206  	org.config.ID = &s.identity.PublicKey
   207  	editChanges, err := org.EditChat(newChatID, &protobuf.CommunityChat{
   208  		Identity:                editedIdentity,
   209  		Permissions:             editedPermissions,
   210  		HideIfPermissionsNotMet: true,
   211  	})
   212  
   213  	s.Require().NoError(err)
   214  
   215  	s.Require().NotNil(description.Chats[newChatID])
   216  	s.Require().NotEmpty(description.Clock)
   217  	s.Require().Equal(editedPermissions, description.Chats[newChatID].Permissions)
   218  	s.Require().Equal(editedIdentity, description.Chats[newChatID].Identity)
   219  
   220  	s.Require().NotNil(editChanges)
   221  	s.Require().NotNil(editChanges.ChatsModified[newChatID])
   222  	s.Require().Equal(editChanges.ChatsModified[newChatID].ChatModified.Identity, editedIdentity)
   223  	s.Require().Equal(editChanges.ChatsModified[newChatID].ChatModified.Permissions, editedPermissions)
   224  	s.Require().Equal(editChanges.ChatsModified[newChatID].ChatModified.HideIfPermissionsNotMet, true)
   225  }
   226  
   227  func (s *CommunitySuite) TestDeleteChat() {
   228  	org := s.buildCommunity(&s.identity.PublicKey)
   229  	org.config.PrivateKey = nil
   230  	org.config.ID = nil
   231  
   232  	_, err := org.DeleteChat(testChatID1)
   233  	s.Require().Equal(ErrNotAuthorized, err)
   234  	change1Clock := org.Clock()
   235  
   236  	org.config.PrivateKey = s.identity
   237  	org.config.ID = &s.identity.PublicKey
   238  
   239  	changes, err := org.DeleteChat(testChatID1)
   240  	s.Require().NoError(err)
   241  	s.Require().NotNil(changes)
   242  	change2Clock := org.Clock()
   243  
   244  	s.Require().Nil(org.Chats()[testChatID1])
   245  	s.Require().Len(changes.ChatsRemoved, 1)
   246  	s.Require().Greater(change2Clock, change1Clock)
   247  }
   248  
   249  func (s *CommunitySuite) TestRemoveUserFromChat() {
   250  	org := s.buildCommunity(&s.identity.PublicKey)
   251  	org.config.PrivateKey = nil
   252  	org.config.ID = nil
   253  	// Not an admin
   254  	_, err := org.RemoveUserFromOrg(&s.member1.PublicKey)
   255  	s.Require().Equal(ErrNotAuthorized, err)
   256  
   257  	// Add admin to community
   258  	org.config.PrivateKey = s.identity
   259  	org.config.ID = &s.identity.PublicKey
   260  
   261  	actualCommunity, err := org.RemoveUserFromChat(&s.member1.PublicKey, testChatID1)
   262  	s.Require().Nil(err)
   263  	s.Require().NotNil(actualCommunity)
   264  
   265  	// Check member has not been removed
   266  	s.Require().True(org.HasMember(&s.member1.PublicKey))
   267  
   268  	// Check member has not been removed from org
   269  	_, ok := actualCommunity.Members[common.PubkeyToHex(&s.member1.PublicKey)]
   270  	s.Require().True(ok)
   271  
   272  	// Check member has been removed from chat
   273  	_, ok = actualCommunity.Chats[testChatID1].Members[common.PubkeyToHex(&s.member1.PublicKey)]
   274  	s.Require().False(ok)
   275  }
   276  
   277  func (s *CommunitySuite) TestRemoveUserFormOrg() {
   278  	org := s.buildCommunity(&s.identity.PublicKey)
   279  	org.config.PrivateKey = nil
   280  	org.config.ID = nil
   281  	// Not an admin
   282  	_, err := org.RemoveUserFromOrg(&s.member1.PublicKey)
   283  	s.Require().Equal(ErrNotAuthorized, err)
   284  
   285  	// Add admin to community
   286  	org.config.PrivateKey = s.identity
   287  	org.config.ID = &s.identity.PublicKey
   288  
   289  	actualCommunity, err := org.RemoveUserFromOrg(&s.member1.PublicKey)
   290  	s.Require().Nil(err)
   291  	s.Require().NotNil(actualCommunity)
   292  
   293  	// Check member has been removed
   294  	s.Require().False(org.HasMember(&s.member1.PublicKey))
   295  
   296  	// Check member has been removed from org
   297  	_, ok := actualCommunity.Members[common.PubkeyToHex(&s.member1.PublicKey)]
   298  	s.Require().False(ok)
   299  
   300  	// Check member has been removed from chat
   301  	_, ok = actualCommunity.Chats[testChatID1].Members[common.PubkeyToHex(&s.member1.PublicKey)]
   302  	s.Require().False(ok)
   303  }
   304  
   305  func (s *CommunitySuite) TestRemoveOurselvesFormOrg() {
   306  	org := s.buildCommunity(&s.identity.PublicKey)
   307  
   308  	// We don't need to be an admin to remove ourselves from community
   309  	org.config.PrivateKey = nil
   310  
   311  	org.RemoveOurselvesFromOrg(&s.member1.PublicKey)
   312  
   313  	// Check member has been removed from org
   314  	s.Require().False(org.HasMember(&s.member1.PublicKey))
   315  
   316  	// Check member has been removed from chat
   317  	_, ok := org.config.CommunityDescription.Chats[testChatID1].Members[common.PubkeyToHex(&s.member1.PublicKey)]
   318  	s.Require().False(ok)
   319  }
   320  
   321  func (s *CommunitySuite) TestAcceptRequestToJoin() {
   322  	// WHAT TO DO WITH ENS
   323  	// TEST CASE 1: Not an admin
   324  	// TEST CASE 2: No request to join
   325  	// TEST CASE 3: Valid
   326  }
   327  
   328  func (s *CommunitySuite) TestDeclineRequestToJoin() {
   329  	// TEST CASE 1: Not an admin
   330  	// TEST CASE 2: No request to join
   331  	// TEST CASE 3: Valid
   332  }
   333  
   334  func (s *CommunitySuite) TestValidateRequestToJoin() {
   335  	description := &protobuf.CommunityDescription{}
   336  
   337  	key, err := crypto.GenerateKey()
   338  	s.Require().NoError(err)
   339  
   340  	signer := &key.PublicKey
   341  
   342  	revealedAccounts := []*protobuf.RevealedAccount{
   343  		&protobuf.RevealedAccount{
   344  			Address: "0x0100000000000000000000000000000000000000"},
   345  	}
   346  
   347  	request := &protobuf.CommunityRequestToJoin{
   348  		EnsName:          "donvanvliet.stateofus.eth",
   349  		CommunityId:      s.communityID,
   350  		Clock:            uint64(time.Now().Unix()),
   351  		RevealedAccounts: revealedAccounts,
   352  	}
   353  
   354  	requestWithChatID := &protobuf.CommunityRequestToJoin{
   355  		EnsName:          "donvanvliet.stateofus.eth",
   356  		CommunityId:      s.communityID,
   357  		ChatId:           testChatID1,
   358  		Clock:            uint64(time.Now().Unix()),
   359  		RevealedAccounts: revealedAccounts,
   360  	}
   361  
   362  	requestWithoutENS := &protobuf.CommunityRequestToJoin{
   363  		CommunityId:      s.communityID,
   364  		Clock:            uint64(time.Now().Unix()),
   365  		RevealedAccounts: revealedAccounts,
   366  	}
   367  
   368  	requestWithChatWithoutENS := &protobuf.CommunityRequestToJoin{
   369  		CommunityId:      s.communityID,
   370  		ChatId:           testChatID1,
   371  		Clock:            uint64(time.Now().Unix()),
   372  		RevealedAccounts: revealedAccounts,
   373  	}
   374  
   375  	// MATRIX
   376  	// NO_MEMBERHSIP - NO_MEMBERSHIP -> Error -> Anyone can join org, chat is read/write for anyone
   377  	// NO_MEMBRISHIP - INVITATION_ONLY -> Error -> Anyone can join org, chat is invitation only
   378  	// NO_MEMBERSHIP - ON_REQUEST -> Success -> Anyone can join org, chat is on request and needs approval
   379  	// INVITATION_ONLY - NO_MEMBERSHIP -> TODO -> Org is invitation only, chat is read-write for members
   380  	// INVITATION_ONLY - INVITATION_ONLY -> Error -> Org is invitation only, chat is invitation only
   381  	// INVITATION_ONLY - ON_REQUEST -> TODO -> Error -> Org is invitation only, member of the org need to request access for chat
   382  	// ON_REQUEST - NO_MEMBRERSHIP -> TODO -> Error -> Org is on request, chat is read write for members
   383  	// ON_REQUEST - INVITATION_ONLY -> Error -> Org is on request, chat is invitation only for members
   384  	// ON_REQUEST - ON_REQUEST -> Fine -> Org is on request, chat is on request
   385  
   386  	testCases := []struct {
   387  		name    string
   388  		config  Config
   389  		request *protobuf.CommunityRequestToJoin
   390  		signer  *ecdsa.PublicKey
   391  		err     error
   392  	}{
   393  		{
   394  			name:    "on-request access to community",
   395  			config:  s.configOnRequest(),
   396  			signer:  signer,
   397  			request: request,
   398  			err:     nil,
   399  		},
   400  		{
   401  			name:    "not admin",
   402  			config:  Config{MemberIdentity: key, CommunityDescription: description},
   403  			signer:  signer,
   404  			request: request,
   405  			err:     ErrNotAdmin,
   406  		},
   407  		{
   408  			name:    "ens-only org and missing ens",
   409  			config:  s.configENSOnly(),
   410  			signer:  signer,
   411  			request: requestWithoutENS,
   412  			err:     ErrCantRequestAccess,
   413  		},
   414  		{
   415  			name:    "ens-only chat and missing ens",
   416  			config:  s.configChatENSOnly(),
   417  			signer:  signer,
   418  			request: requestWithChatWithoutENS,
   419  			err:     ErrCantRequestAccess,
   420  		},
   421  		{
   422  			name:    "missing chat",
   423  			config:  s.configOnRequest(),
   424  			signer:  signer,
   425  			request: requestWithChatID,
   426  			err:     ErrChatNotFound,
   427  		},
   428  		// Org-Chat combinations
   429  		// NO_MEMBERSHIP-NO_MEMBERSHIP = error as you should not be
   430  		// requesting access
   431  		{
   432  			name:    "no-membership org with no-membeship chat",
   433  			config:  s.configNoMembershipOrgNoMembershipChat(),
   434  			signer:  signer,
   435  			request: requestWithChatID,
   436  			err:     ErrCantRequestAccess,
   437  		},
   438  		// NO_MEMBERSHIP-ON_REQUEST = this is a valid case
   439  		{
   440  			name:    "no-membership org with on-request chat",
   441  			config:  s.configNoMembershipOrgOnRequestChat(),
   442  			signer:  signer,
   443  			request: requestWithChatID,
   444  		},
   445  		// ON_REQUEST-ON_REQUEST success
   446  		{
   447  			name:    "on-request org with on-request chat",
   448  			config:  s.configOnRequestOrgOnRequestChat(),
   449  			signer:  signer,
   450  			request: requestWithChatID,
   451  		},
   452  	}
   453  
   454  	for _, tc := range testCases {
   455  		s.Run(tc.name, func() {
   456  			org, err := New(tc.config, &TimeSourceStub{}, &DescriptionEncryptorMock{}, nil)
   457  			s.Require().NoError(err)
   458  			err = org.ValidateRequestToJoin(tc.signer, tc.request)
   459  			s.Require().Equal(tc.err, err)
   460  		})
   461  	}
   462  }
   463  
   464  func (s *CommunitySuite) TestCanPostCanView() {
   465  	chatID := "chat-id"
   466  	memberKey := common.PubkeyToHex(&s.member1.PublicKey)
   467  	// Member has no channel role
   468  	description := &protobuf.CommunityDescription{
   469  		Members: map[string]*protobuf.CommunityMember{
   470  			memberKey: &protobuf.CommunityMember{},
   471  		},
   472  		Chats: map[string]*protobuf.CommunityChat{
   473  			chatID: &protobuf.CommunityChat{
   474  				Members: map[string]*protobuf.CommunityMember{
   475  					memberKey: &protobuf.CommunityMember{},
   476  				},
   477  			},
   478  		},
   479  	}
   480  
   481  	community := &Community{config: &Config{ID: &s.member2.PublicKey}}
   482  	community.config.CommunityDescription = description
   483  
   484  	result, err := community.CanPost(&s.member1.PublicKey, chatID, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
   485  	s.Require().NoError(err)
   486  	s.Require().True(result)
   487  
   488  	result = community.CanView(&s.member1.PublicKey, chatID)
   489  	s.Require().True(result)
   490  
   491  	// member has view channel permissions
   492  	description.Chats[chatID].Members[memberKey].ChannelRole = protobuf.CommunityMember_CHANNEL_ROLE_VIEWER
   493  
   494  	result, err = community.CanPost(&s.member1.PublicKey, chatID, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
   495  	s.Require().NoError(err)
   496  	s.Require().False(result)
   497  
   498  	result = community.CanView(&s.member1.PublicKey, chatID)
   499  	s.Require().True(result)
   500  }
   501  
   502  func (s *CommunitySuite) TestCanPost() {
   503  	notMember := &s.member3.PublicKey
   504  	member := &s.member1.PublicKey
   505  
   506  	testCases := []struct {
   507  		name    string
   508  		config  Config
   509  		member  *ecdsa.PublicKey
   510  		err     error
   511  		canPost bool
   512  	}{
   513  		{
   514  			name:    "no-membership org with no-membership chat",
   515  			config:  s.configNoMembershipOrgNoMembershipChat(),
   516  			member:  notMember,
   517  			canPost: false,
   518  		},
   519  		{
   520  			name:    "membership org with no-membership chat-not-a-member",
   521  			config:  s.configOnRequestOrgNoMembershipChat(),
   522  			member:  notMember,
   523  			canPost: false,
   524  		},
   525  		{
   526  			name:    "membership org with no-membership chat",
   527  			config:  s.configOnRequestOrgNoMembershipChat(),
   528  			member:  member,
   529  			canPost: true,
   530  		},
   531  		{
   532  			name:    "creator can always post of course",
   533  			config:  s.configOnRequestOrgNoMembershipChat(),
   534  			member:  &s.identity.PublicKey,
   535  			canPost: true,
   536  		},
   537  	}
   538  
   539  	for _, tc := range testCases {
   540  		s.Run(tc.name, func() {
   541  			var err error
   542  			org, err := New(tc.config, &TimeSourceStub{}, &DescriptionEncryptorMock{}, nil)
   543  			s.Require().NoError(err)
   544  
   545  			canPost, err := org.CanPost(tc.member, testChatID1, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
   546  			s.Require().Equal(tc.err, err)
   547  			s.Require().Equal(tc.canPost, canPost)
   548  		})
   549  	}
   550  }
   551  
   552  func (s *CommunitySuite) TestHandleCommunityDescription() {
   553  	key, err := crypto.GenerateKey()
   554  	s.Require().NoError(err)
   555  
   556  	signer := &key.PublicKey
   557  
   558  	buildChanges := func(c *Community) *CommunityChanges {
   559  		return c.emptyCommunityChanges()
   560  	}
   561  
   562  	testCases := []struct {
   563  		name        string
   564  		description func(*Community) *protobuf.CommunityDescription
   565  		changes     func(*Community) *CommunityChanges
   566  		signer      *ecdsa.PublicKey
   567  		err         error
   568  	}{
   569  		{
   570  			name:        "updated version but no changes",
   571  			description: s.identicalCommunityDescription,
   572  			signer:      signer,
   573  			changes:     buildChanges,
   574  			err:         nil,
   575  		},
   576  		{
   577  			name:        "updated version but lower clock",
   578  			description: s.oldCommunityDescription,
   579  			signer:      signer,
   580  			changes:     func(c *Community) *CommunityChanges { return nil },
   581  			err:         ErrInvalidCommunityDescriptionClockOutdated,
   582  		},
   583  		{
   584  			name:        "removed member from org",
   585  			description: s.removedMemberCommunityDescription,
   586  			signer:      signer,
   587  			changes: func(org *Community) *CommunityChanges {
   588  				changes := org.emptyCommunityChanges()
   589  				changes.MembersRemoved[s.member1Key] = &protobuf.CommunityMember{}
   590  				changes.ChatsModified[testChatID1] = &CommunityChatChanges{
   591  					MembersAdded:   make(map[string]*protobuf.CommunityMember),
   592  					MembersRemoved: make(map[string]*protobuf.CommunityMember),
   593  				}
   594  				changes.ChatsModified[testChatID1].MembersRemoved[s.member1Key] = &protobuf.CommunityMember{}
   595  
   596  				return changes
   597  			},
   598  			err: nil,
   599  		},
   600  		{
   601  			name:        "added member from org",
   602  			description: s.addedMemberCommunityDescription,
   603  			signer:      signer,
   604  			changes: func(org *Community) *CommunityChanges {
   605  				changes := org.emptyCommunityChanges()
   606  				changes.MembersAdded[s.member3Key] = &protobuf.CommunityMember{}
   607  				changes.ChatsModified[testChatID1] = &CommunityChatChanges{
   608  					MembersAdded:   make(map[string]*protobuf.CommunityMember),
   609  					MembersRemoved: make(map[string]*protobuf.CommunityMember),
   610  				}
   611  				changes.ChatsModified[testChatID1].MembersAdded[s.member3Key] = &protobuf.CommunityMember{}
   612  
   613  				return changes
   614  			},
   615  			err: nil,
   616  		},
   617  		{
   618  			name:        "chat added to org",
   619  			description: s.addedChatCommunityDescription,
   620  			signer:      signer,
   621  			changes: func(org *Community) *CommunityChanges {
   622  				changes := org.emptyCommunityChanges()
   623  				changes.MembersAdded[s.member3Key] = &protobuf.CommunityMember{}
   624  				changes.ChatsAdded[testChatID2] = &protobuf.CommunityChat{
   625  					Identity:    &protobuf.ChatIdentity{DisplayName: "added-chat", Description: "description"},
   626  					Permissions: &protobuf.CommunityPermissions{Access: protobuf.CommunityPermissions_MANUAL_ACCEPT},
   627  					Members:     make(map[string]*protobuf.CommunityMember)}
   628  				changes.ChatsAdded[testChatID2].Members[s.member3Key] = &protobuf.CommunityMember{}
   629  
   630  				return changes
   631  			},
   632  			err: nil,
   633  		},
   634  		{
   635  			name:        "chat removed from the org",
   636  			description: s.removedChatCommunityDescription,
   637  			signer:      signer,
   638  			changes: func(org *Community) *CommunityChanges {
   639  				changes := org.emptyCommunityChanges()
   640  				changes.ChatsRemoved[testChatID1] = org.config.CommunityDescription.Chats[testChatID1]
   641  
   642  				return changes
   643  			},
   644  			err: nil,
   645  		},
   646  	}
   647  
   648  	for _, tc := range testCases {
   649  		s.Run(tc.name, func() {
   650  			org := s.buildCommunity(signer)
   651  			org.Join()
   652  			expectedChanges := tc.changes(org)
   653  			actualChanges, err := org.UpdateCommunityDescription(tc.description(org), []byte{0x01}, nil)
   654  			s.Require().Equal(tc.err, err)
   655  			s.Require().Equal(expectedChanges, actualChanges)
   656  		})
   657  	}
   658  }
   659  
   660  func (s *CommunitySuite) TestValidateCommunityDescription() {
   661  
   662  	testCases := []struct {
   663  		name        string
   664  		description *protobuf.CommunityDescription
   665  		err         error
   666  	}{
   667  		{
   668  			name:        "valid",
   669  			description: s.buildCommunityDescription(),
   670  			err:         nil,
   671  		},
   672  		{
   673  			name: "empty description",
   674  			err:  ErrInvalidCommunityDescription,
   675  		},
   676  		{
   677  			name:        "empty org permissions",
   678  			description: s.emptyPermissionsCommunityDescription(),
   679  			err:         ErrInvalidCommunityDescriptionNoOrgPermissions,
   680  		},
   681  		{
   682  			name:        "empty chat permissions",
   683  			description: s.emptyChatPermissionsCommunityDescription(),
   684  			err:         ErrInvalidCommunityDescriptionNoChatPermissions,
   685  		},
   686  		{
   687  			name:        "unknown org permissions",
   688  			description: s.unknownOrgPermissionsCommunityDescription(),
   689  			err:         ErrInvalidCommunityDescriptionUnknownOrgAccess,
   690  		},
   691  		{
   692  			name:        "unknown chat permissions",
   693  			description: s.unknownChatPermissionsCommunityDescription(),
   694  			err:         ErrInvalidCommunityDescriptionUnknownChatAccess,
   695  		},
   696  		{
   697  			name:        "member in chat but not in org",
   698  			description: s.memberInChatNotInOrgCommunityDescription(),
   699  			err:         ErrInvalidCommunityDescriptionMemberInChatButNotInOrg,
   700  		},
   701  	}
   702  
   703  	for _, tc := range testCases {
   704  		s.Run(tc.name, func() {
   705  			err := ValidateCommunityDescription(tc.description)
   706  			s.Require().Equal(tc.err, err)
   707  		})
   708  	}
   709  }
   710  
   711  func (s *CommunitySuite) TestChatIDs() {
   712  	community := s.buildCommunity(&s.identity.PublicKey)
   713  	chatIDs := community.ChatIDs()
   714  
   715  	s.Require().Len(chatIDs, 1)
   716  }
   717  
   718  func (s *CommunitySuite) TestChannelTokenPermissionsByType() {
   719  	org := s.buildCommunity(&s.identity.PublicKey)
   720  
   721  	viewOnlyPermissions := []*protobuf.CommunityTokenPermission{
   722  		&protobuf.CommunityTokenPermission{
   723  			Id:            "some-id",
   724  			Type:          protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
   725  			TokenCriteria: make([]*protobuf.TokenCriteria, 0),
   726  			ChatIds:       []string{"some-chat-id"},
   727  		},
   728  	}
   729  
   730  	viewAndPostPermissions := []*protobuf.CommunityTokenPermission{
   731  		&protobuf.CommunityTokenPermission{
   732  			Id:            "some-other-id",
   733  			Type:          protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL,
   734  			TokenCriteria: make([]*protobuf.TokenCriteria, 0),
   735  			ChatIds:       []string{"some-chat-id-2"},
   736  		},
   737  	}
   738  
   739  	for _, viewOnlyPermission := range viewOnlyPermissions {
   740  		_, err := org.UpsertTokenPermission(viewOnlyPermission)
   741  		s.Require().NoError(err)
   742  	}
   743  	for _, viewAndPostPermission := range viewAndPostPermissions {
   744  		_, err := org.UpsertTokenPermission(viewAndPostPermission)
   745  		s.Require().NoError(err)
   746  	}
   747  
   748  	result := org.ChannelTokenPermissionsByType("some-chat-id", protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL)
   749  	s.Require().Len(result, 1)
   750  	s.Require().Equal(result[0].Id, viewOnlyPermissions[0].Id)
   751  	s.Require().Equal(result[0].TokenCriteria, viewOnlyPermissions[0].TokenCriteria)
   752  	s.Require().Equal(result[0].ChatIds, viewOnlyPermissions[0].ChatIds)
   753  
   754  	result = org.ChannelTokenPermissionsByType("some-chat-id-2", protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL)
   755  	s.Require().Len(result, 1)
   756  	s.Require().Equal(result[0].Id, viewAndPostPermissions[0].Id)
   757  	s.Require().Equal(result[0].TokenCriteria, viewAndPostPermissions[0].TokenCriteria)
   758  	s.Require().Equal(result[0].ChatIds, viewAndPostPermissions[0].ChatIds)
   759  }
   760  
   761  func (s *CommunitySuite) TestChannelEncrypted() {
   762  	org := s.buildCommunity(&s.identity.PublicKey)
   763  	someChannelID := "some-channel-id"
   764  	someChatID := org.ChatID(someChannelID)
   765  
   766  	s.Require().False(org.ChannelEncrypted(someChannelID))
   767  
   768  	_, err := org.UpsertTokenPermission(&protobuf.CommunityTokenPermission{
   769  		Id:            "A",
   770  		Type:          protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL,
   771  		TokenCriteria: []*protobuf.TokenCriteria{},
   772  		ChatIds:       []string{someChatID},
   773  	})
   774  	s.Require().NoError(err)
   775  	s.Require().True(org.channelEncrypted(someChannelID))
   776  
   777  	_, err = org.UpsertTokenPermission(&protobuf.CommunityTokenPermission{
   778  		Id:            "B",
   779  		Type:          protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
   780  		TokenCriteria: []*protobuf.TokenCriteria{&protobuf.TokenCriteria{}},
   781  		ChatIds:       []string{someChatID},
   782  	})
   783  	s.Require().NoError(err)
   784  	s.Require().True(org.channelEncrypted(someChannelID))
   785  
   786  	// Channels with `view` permission without token requirements shouldn't be encrypted.
   787  	// See: https://github.com/status-im/status-desktop/issues/14748
   788  	_, err = org.UpsertTokenPermission(&protobuf.CommunityTokenPermission{
   789  		Id:            "C",
   790  		Type:          protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
   791  		TokenCriteria: []*protobuf.TokenCriteria{},
   792  		ChatIds:       []string{someChatID},
   793  	})
   794  	s.Require().NoError(err)
   795  	s.Require().False(org.channelEncrypted(someChannelID))
   796  }
   797  
   798  func (s *CommunitySuite) emptyCommunityDescription() *protobuf.CommunityDescription {
   799  	return &protobuf.CommunityDescription{
   800  		Permissions: &protobuf.CommunityPermissions{},
   801  	}
   802  
   803  }
   804  
   805  func (s *CommunitySuite) emptyCommunityDescriptionWithChat() *protobuf.CommunityDescription {
   806  	desc := &protobuf.CommunityDescription{
   807  		Members:     make(map[string]*protobuf.CommunityMember),
   808  		Clock:       1,
   809  		Chats:       make(map[string]*protobuf.CommunityChat),
   810  		Categories:  make(map[string]*protobuf.CommunityCategory),
   811  		Permissions: &protobuf.CommunityPermissions{},
   812  	}
   813  
   814  	desc.Categories[testCategoryID1] = &protobuf.CommunityCategory{CategoryId: testCategoryID1, Name: testCategoryName1, Position: 0}
   815  	desc.Chats[testChatID1] = &protobuf.CommunityChat{Position: 0, Permissions: &protobuf.CommunityPermissions{}, Members: make(map[string]*protobuf.CommunityMember)}
   816  	desc.Members[common.PubkeyToHex(&s.member1.PublicKey)] = &protobuf.CommunityMember{}
   817  	desc.Chats[testChatID1].Members[common.PubkeyToHex(&s.member1.PublicKey)] = &protobuf.CommunityMember{}
   818  
   819  	return desc
   820  
   821  }
   822  
   823  func (s *CommunitySuite) newConfig(identity *ecdsa.PrivateKey, description *protobuf.CommunityDescription) Config {
   824  	return Config{
   825  		MemberIdentity:       identity,
   826  		ID:                   &identity.PublicKey,
   827  		CommunityDescription: description,
   828  		PrivateKey:           identity,
   829  		ControlNode:          &identity.PublicKey,
   830  		ControlDevice:        true,
   831  	}
   832  }
   833  
   834  func (s *CommunitySuite) configOnRequest() Config {
   835  	description := s.emptyCommunityDescription()
   836  	description.Permissions.Access = protobuf.CommunityPermissions_MANUAL_ACCEPT
   837  	return s.newConfig(s.identity, description)
   838  }
   839  
   840  func (s *CommunitySuite) configNoMembershipOrgNoMembershipChat() Config {
   841  	description := s.emptyCommunityDescriptionWithChat()
   842  	description.Permissions.Access = protobuf.CommunityPermissions_AUTO_ACCEPT
   843  	description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_AUTO_ACCEPT
   844  	return s.newConfig(s.identity, description)
   845  }
   846  
   847  func (s *CommunitySuite) configNoMembershipOrgOnRequestChat() Config {
   848  	description := s.emptyCommunityDescriptionWithChat()
   849  	description.Permissions.Access = protobuf.CommunityPermissions_AUTO_ACCEPT
   850  	description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_MANUAL_ACCEPT
   851  	return s.newConfig(s.identity, description)
   852  }
   853  
   854  func (s *CommunitySuite) configOnRequestOrgOnRequestChat() Config {
   855  	description := s.emptyCommunityDescriptionWithChat()
   856  	description.Permissions.Access = protobuf.CommunityPermissions_MANUAL_ACCEPT
   857  	description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_MANUAL_ACCEPT
   858  	return s.newConfig(s.identity, description)
   859  }
   860  
   861  func (s *CommunitySuite) configOnRequestOrgNoMembershipChat() Config {
   862  	description := s.emptyCommunityDescriptionWithChat()
   863  	description.Permissions.Access = protobuf.CommunityPermissions_MANUAL_ACCEPT
   864  	description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_AUTO_ACCEPT
   865  	return s.newConfig(s.identity, description)
   866  }
   867  
   868  func (s *CommunitySuite) configChatENSOnly() Config {
   869  	description := s.emptyCommunityDescriptionWithChat()
   870  	description.Permissions.Access = protobuf.CommunityPermissions_MANUAL_ACCEPT
   871  	description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_MANUAL_ACCEPT
   872  	description.Chats[testChatID1].Permissions.EnsOnly = true
   873  	return s.newConfig(s.identity, description)
   874  }
   875  
   876  func (s *CommunitySuite) configENSOnly() Config {
   877  	description := s.emptyCommunityDescription()
   878  	description.Permissions.Access = protobuf.CommunityPermissions_MANUAL_ACCEPT
   879  	description.Permissions.EnsOnly = true
   880  	return s.newConfig(s.identity, description)
   881  }
   882  
   883  func (s *CommunitySuite) config() Config {
   884  	config := s.configOnRequestOrgOnRequestChat()
   885  	return config
   886  }
   887  
   888  func (s *CommunitySuite) buildCommunityDescription() *protobuf.CommunityDescription {
   889  	config := s.configOnRequestOrgOnRequestChat()
   890  	desc := config.CommunityDescription
   891  	desc.Clock = 1
   892  	desc.Members = make(map[string]*protobuf.CommunityMember)
   893  	desc.Members[s.member1Key] = &protobuf.CommunityMember{}
   894  	desc.Members[s.member2Key] = &protobuf.CommunityMember{}
   895  	desc.Chats[testChatID1].Members = make(map[string]*protobuf.CommunityMember)
   896  	desc.Chats[testChatID1].Members[s.member1Key] = &protobuf.CommunityMember{}
   897  	desc.Chats[testChatID1].Identity = &protobuf.ChatIdentity{
   898  		DisplayName: "display-name",
   899  		Description: "description",
   900  	}
   901  	return desc
   902  }
   903  
   904  func (s *CommunitySuite) emptyPermissionsCommunityDescription() *protobuf.CommunityDescription {
   905  	desc := s.buildCommunityDescription()
   906  	desc.Permissions = nil
   907  	return desc
   908  }
   909  
   910  func (s *CommunitySuite) emptyChatPermissionsCommunityDescription() *protobuf.CommunityDescription {
   911  	desc := s.buildCommunityDescription()
   912  	desc.Chats[testChatID1].Permissions = nil
   913  	return desc
   914  }
   915  
   916  func (s *CommunitySuite) unknownOrgPermissionsCommunityDescription() *protobuf.CommunityDescription {
   917  	desc := s.buildCommunityDescription()
   918  	desc.Permissions.Access = protobuf.CommunityPermissions_UNKNOWN_ACCESS
   919  	return desc
   920  }
   921  
   922  func (s *CommunitySuite) unknownChatPermissionsCommunityDescription() *protobuf.CommunityDescription {
   923  	desc := s.buildCommunityDescription()
   924  	desc.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_UNKNOWN_ACCESS
   925  	return desc
   926  }
   927  
   928  func (s *CommunitySuite) memberInChatNotInOrgCommunityDescription() *protobuf.CommunityDescription {
   929  	desc := s.buildCommunityDescription()
   930  	desc.Chats[testChatID1].Members[s.member3Key] = &protobuf.CommunityMember{}
   931  	return desc
   932  }
   933  
   934  func (s *CommunitySuite) buildCommunity(owner *ecdsa.PublicKey) *Community {
   935  	config := s.config()
   936  	config.ID = owner
   937  	config.CommunityDescription = s.buildCommunityDescription()
   938  
   939  	org, err := New(config, &TimeSourceStub{}, &DescriptionEncryptorMock{}, nil)
   940  	s.Require().NoError(err)
   941  	return org
   942  }
   943  
   944  func (s *CommunitySuite) identicalCommunityDescription(org *Community) *protobuf.CommunityDescription {
   945  	description := proto.Clone(org.config.CommunityDescription).(*protobuf.CommunityDescription)
   946  	description.Clock++
   947  	return description
   948  }
   949  
   950  func (s *CommunitySuite) oldCommunityDescription(org *Community) *protobuf.CommunityDescription {
   951  	description := proto.Clone(org.config.CommunityDescription).(*protobuf.CommunityDescription)
   952  	description.Clock--
   953  	delete(description.Members, s.member1Key)
   954  	delete(description.Chats[testChatID1].Members, s.member1Key)
   955  	return description
   956  }
   957  
   958  func (s *CommunitySuite) removedMemberCommunityDescription(org *Community) *protobuf.CommunityDescription {
   959  	description := proto.Clone(org.config.CommunityDescription).(*protobuf.CommunityDescription)
   960  	description.Clock++
   961  	delete(description.Members, s.member1Key)
   962  	delete(description.Chats[testChatID1].Members, s.member1Key)
   963  	return description
   964  }
   965  
   966  func (s *CommunitySuite) addedMemberCommunityDescription(org *Community) *protobuf.CommunityDescription {
   967  	description := proto.Clone(org.config.CommunityDescription).(*protobuf.CommunityDescription)
   968  	description.Clock++
   969  	description.Members[s.member3Key] = &protobuf.CommunityMember{}
   970  	description.Chats[testChatID1].Members[s.member3Key] = &protobuf.CommunityMember{}
   971  
   972  	return description
   973  }
   974  
   975  func (s *CommunitySuite) addedChatCommunityDescription(org *Community) *protobuf.CommunityDescription {
   976  	description := proto.Clone(org.config.CommunityDescription).(*protobuf.CommunityDescription)
   977  	description.Clock++
   978  	description.Members[s.member3Key] = &protobuf.CommunityMember{}
   979  	description.Chats[testChatID2] = &protobuf.CommunityChat{
   980  		Identity:    &protobuf.ChatIdentity{DisplayName: "added-chat", Description: "description"},
   981  		Permissions: &protobuf.CommunityPermissions{Access: protobuf.CommunityPermissions_MANUAL_ACCEPT},
   982  		Members:     make(map[string]*protobuf.CommunityMember)}
   983  	description.Chats[testChatID2].Members[s.member3Key] = &protobuf.CommunityMember{}
   984  
   985  	return description
   986  }
   987  
   988  func (s *CommunitySuite) removedChatCommunityDescription(org *Community) *protobuf.CommunityDescription {
   989  	description := proto.Clone(org.config.CommunityDescription).(*protobuf.CommunityDescription)
   990  	description.Clock++
   991  	delete(description.Chats, testChatID1)
   992  
   993  	return description
   994  }
   995  
   996  func (s *CommunitySuite) TestMarshalJSON() {
   997  	community := s.buildCommunity(&s.identity.PublicKey)
   998  	channelID := community.ChatID(testChatID1)
   999  	_, err := community.UpsertTokenPermission(&protobuf.CommunityTokenPermission{
  1000  		Id:            "A",
  1001  		Type:          protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL,
  1002  		TokenCriteria: []*protobuf.TokenCriteria{},
  1003  		ChatIds:       []string{channelID},
  1004  	})
  1005  	s.Require().NoError(err)
  1006  
  1007  	s.Require().True(community.ChannelEncrypted(testChatID1))
  1008  
  1009  	communityDescription := community.config.CommunityDescription
  1010  	ownerKey := s.identity
  1011  	s.Require().NoError(err)
  1012  
  1013  	memberKey, err := crypto.GenerateKey()
  1014  	s.Require().NoError(err)
  1015  
  1016  	// returns true if the user is the owner
  1017  
  1018  	communityDescription.Members = make(map[string]*protobuf.CommunityMember)
  1019  	communityDescription.Members[common.PubkeyToHex(&ownerKey.PublicKey)] = &protobuf.CommunityMember{Roles: []protobuf.CommunityMember_Roles{protobuf.CommunityMember_ROLE_OWNER}}
  1020  	communityDescription.Members[common.PubkeyToHex(&memberKey.PublicKey)] = &protobuf.CommunityMember{Roles: []protobuf.CommunityMember_Roles{protobuf.CommunityMember_ROLE_ADMIN}}
  1021  	communityDescription.Chats[testChatID1] = &protobuf.CommunityChat{Members: make(map[string]*protobuf.CommunityMember), Identity: &protobuf.ChatIdentity{}}
  1022  	communityDescription.Chats[testChatID1].Members[common.PubkeyToHex(&ownerKey.PublicKey)] = &protobuf.CommunityMember{Roles: []protobuf.CommunityMember_Roles{protobuf.CommunityMember_ROLE_OWNER}}
  1023  
  1024  	// Test token gated community
  1025  	s.Require().True(community.ChannelEncrypted(testChatID1))
  1026  	communityJSON, err := json.Marshal(community)
  1027  	s.Require().NoError(err)
  1028  
  1029  	var communityData map[string]interface{}
  1030  	err = json.Unmarshal(communityJSON, &communityData)
  1031  	s.Require().NoError(err)
  1032  	s.Require().NotNil(communityData["chats"])
  1033  
  1034  	expectedChats := map[string]interface{}{}
  1035  	expectedChat := map[string]interface{}{
  1036  		"canPost":                 true,
  1037  		"canPostReactions":        true,
  1038  		"categoryID":              "",
  1039  		"canView":                 true,
  1040  		"color":                   "",
  1041  		"description":             "",
  1042  		"emoji":                   "",
  1043  		"hideIfPermissionsNotMet": false,
  1044  		"members": map[string]interface{}{
  1045  			common.PubkeyToHex(&ownerKey.PublicKey): map[string]interface{}{
  1046  				"roles": []interface{}{float64(1)},
  1047  			},
  1048  		},
  1049  		"id":                      testChatID1,
  1050  		"name":                    "",
  1051  		"permissions":             nil,
  1052  		"position":                float64(0),
  1053  		"tokenGated":              true,
  1054  		"viewersCanPostReactions": false,
  1055  		"missingEncryptionKey":    false,
  1056  	}
  1057  
  1058  	expectedChats[testChatID1] = expectedChat
  1059  	s.Require().Equal(expectedChats, communityData["chats"])
  1060  
  1061  	// Test token gated community
  1062  	community.config.CommunityDescription.TokenPermissions = nil
  1063  	communityJSON, err = json.Marshal(community)
  1064  	s.Require().NoError(err)
  1065  
  1066  	err = json.Unmarshal(communityJSON, &communityData)
  1067  	s.Require().NoError(err)
  1068  	s.Require().NotNil(communityData["chats"])
  1069  
  1070  	expectedChats = map[string]interface{}{}
  1071  	expectedChat = map[string]interface{}{
  1072  		"canPost":                 true,
  1073  		"canPostReactions":        true,
  1074  		"categoryID":              "",
  1075  		"canView":                 true,
  1076  		"color":                   "",
  1077  		"description":             "",
  1078  		"emoji":                   "",
  1079  		"hideIfPermissionsNotMet": false,
  1080  		"id":                      testChatID1,
  1081  		"members":                 nil,
  1082  		"name":                    "",
  1083  		"permissions":             nil,
  1084  		"position":                float64(0),
  1085  		"tokenGated":              false,
  1086  		"viewersCanPostReactions": false,
  1087  		"missingEncryptionKey":    false,
  1088  	}
  1089  
  1090  	expectedChats[testChatID1] = expectedChat
  1091  	s.Require().Equal(expectedChats, communityData["chats"])
  1092  }