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

     1  package communities
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/ecdsa"
     7  	"database/sql"
     8  	"encoding/hex"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"os"
    12  	"strconv"
    13  	"strings"
    14  	"sync"
    15  	"time"
    16  
    17  	"github.com/golang/protobuf/proto"
    18  
    19  	"github.com/google/uuid"
    20  	"github.com/pkg/errors"
    21  	"go.uber.org/zap"
    22  
    23  	gethcommon "github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/common/hexutil"
    25  	"github.com/status-im/status-go/account"
    26  	utils "github.com/status-im/status-go/common"
    27  	"github.com/status-im/status-go/eth-node/crypto"
    28  	"github.com/status-im/status-go/eth-node/types"
    29  	"github.com/status-im/status-go/images"
    30  	multiaccountscommon "github.com/status-im/status-go/multiaccounts/common"
    31  	"github.com/status-im/status-go/params"
    32  	"github.com/status-im/status-go/protocol/common"
    33  	"github.com/status-im/status-go/protocol/common/shard"
    34  	community_token "github.com/status-im/status-go/protocol/communities/token"
    35  	"github.com/status-im/status-go/protocol/encryption"
    36  	"github.com/status-im/status-go/protocol/ens"
    37  	"github.com/status-im/status-go/protocol/protobuf"
    38  	"github.com/status-im/status-go/protocol/requests"
    39  	"github.com/status-im/status-go/protocol/transport"
    40  	"github.com/status-im/status-go/rpc/network"
    41  	"github.com/status-im/status-go/server"
    42  	"github.com/status-im/status-go/services/wallet/bigint"
    43  	walletcommon "github.com/status-im/status-go/services/wallet/common"
    44  	"github.com/status-im/status-go/services/wallet/thirdparty"
    45  	"github.com/status-im/status-go/services/wallet/token"
    46  	"github.com/status-im/status-go/signal"
    47  	"github.com/status-im/status-go/transactions"
    48  )
    49  
    50  type Publisher interface {
    51  	publish(subscription *Subscription)
    52  }
    53  
    54  var defaultAnnounceList = [][]string{
    55  	{"udp://tracker.opentrackr.org:1337/announce"},
    56  	{"udp://tracker.openbittorrent.com:6969/announce"},
    57  }
    58  var pieceLength = 100 * 1024
    59  
    60  const maxArchiveSizeInBytes = 30000000
    61  
    62  var maxNbMembers = 5000
    63  var maxNbPendingRequestedMembers = 100
    64  
    65  var memberPermissionsCheckInterval = 8 * time.Hour
    66  var validateInterval = 2 * time.Minute
    67  
    68  // Used for testing only
    69  func SetValidateInterval(duration time.Duration) {
    70  	validateInterval = duration
    71  }
    72  func SetMaxNbMembers(maxNb int) {
    73  	maxNbMembers = maxNb
    74  }
    75  func SetMaxNbPendingRequestedMembers(maxNb int) {
    76  	maxNbPendingRequestedMembers = maxNb
    77  }
    78  
    79  // errors
    80  var (
    81  	ErrTorrentTimedout                 = errors.New("torrent has timed out")
    82  	ErrCommunityRequestAlreadyRejected = errors.New("that user was already rejected from the community")
    83  	ErrInvalidClock                    = errors.New("invalid clock to cancel request to join")
    84  )
    85  
    86  type Manager struct {
    87  	persistence              *Persistence
    88  	encryptor                *encryption.Protocol
    89  	ensSubscription          chan []*ens.VerificationRecord
    90  	subscriptions            []chan *Subscription
    91  	ensVerifier              *ens.Verifier
    92  	ownerVerifier            OwnerVerifier
    93  	identity                 *ecdsa.PrivateKey
    94  	installationID           string
    95  	accountsManager          account.Manager
    96  	tokenManager             TokenManager
    97  	collectiblesManager      CollectiblesManager
    98  	logger                   *zap.Logger
    99  	transport                *transport.Transport
   100  	timesource               common.TimeSource
   101  	quit                     chan struct{}
   102  	walletConfig             *params.WalletConfig
   103  	communityTokensService   CommunityTokensServiceInterface
   104  	membersReevaluationTasks sync.Map // stores `membersReevaluationTask`
   105  	forceMembersReevaluation map[string]chan struct{}
   106  	stopped                  bool
   107  	RekeyInterval            time.Duration
   108  	PermissionChecker        PermissionChecker
   109  	keyDistributor           KeyDistributor
   110  	communityLock            *CommunityLock
   111  	mediaServer              server.MediaServerInterface
   112  }
   113  
   114  type CommunityLock struct {
   115  	logger *zap.Logger
   116  	locks  map[string]*sync.Mutex
   117  	mutex  sync.Mutex
   118  }
   119  
   120  func NewCommunityLock(logger *zap.Logger) *CommunityLock {
   121  	return &CommunityLock{
   122  		logger: logger.Named("CommunityLock"),
   123  		locks:  make(map[string]*sync.Mutex),
   124  	}
   125  }
   126  
   127  func (c *CommunityLock) Lock(communityID types.HexBytes) {
   128  	c.mutex.Lock()
   129  	communityIDStr := types.EncodeHex(communityID)
   130  	lock, ok := c.locks[communityIDStr]
   131  	if !ok {
   132  		lock = &sync.Mutex{}
   133  		c.locks[communityIDStr] = lock
   134  	}
   135  	c.mutex.Unlock()
   136  
   137  	lock.Lock()
   138  }
   139  
   140  func (c *CommunityLock) Unlock(communityID types.HexBytes) {
   141  	c.mutex.Lock()
   142  	communityIDStr := types.EncodeHex(communityID)
   143  	lock, ok := c.locks[communityIDStr]
   144  	c.mutex.Unlock()
   145  
   146  	if ok {
   147  		lock.Unlock()
   148  	} else {
   149  		c.logger.Warn("trying to unlock a non-existent lock", zap.String("communityID", communityIDStr))
   150  	}
   151  }
   152  
   153  func (c *CommunityLock) Init() {
   154  	c.locks = make(map[string]*sync.Mutex)
   155  }
   156  
   157  type HistoryArchiveDownloadTask struct {
   158  	CancelChan chan struct{}
   159  	Waiter     sync.WaitGroup
   160  	m          sync.RWMutex
   161  	Cancelled  bool
   162  }
   163  
   164  type HistoryArchiveDownloadTaskInfo struct {
   165  	TotalDownloadedArchivesCount int
   166  	TotalArchivesCount           int
   167  	Cancelled                    bool
   168  }
   169  
   170  type ArchiveFileService interface {
   171  	CreateHistoryArchiveTorrentFromMessages(communityID types.HexBytes, messages []*types.Message, topics []types.TopicType, startDate time.Time, endDate time.Time, partition time.Duration, encrypt bool) ([]string, error)
   172  	CreateHistoryArchiveTorrentFromDB(communityID types.HexBytes, topics []types.TopicType, startDate time.Time, endDate time.Time, partition time.Duration, encrypt bool) ([]string, error)
   173  	SaveMessageArchiveID(communityID types.HexBytes, hash string) error
   174  	GetMessageArchiveIDsToImport(communityID types.HexBytes) ([]string, error)
   175  	SetMessageArchiveIDImported(communityID types.HexBytes, hash string, imported bool) error
   176  	ExtractMessagesFromHistoryArchive(communityID types.HexBytes, archiveID string) ([]*protobuf.WakuMessage, error)
   177  	GetHistoryArchiveMagnetlink(communityID types.HexBytes) (string, error)
   178  	LoadHistoryArchiveIndexFromFile(myKey *ecdsa.PrivateKey, communityID types.HexBytes) (*protobuf.WakuMessageArchiveIndex, error)
   179  }
   180  
   181  type ArchiveService interface {
   182  	ArchiveFileService
   183  
   184  	SetOnline(bool)
   185  	SetTorrentConfig(*params.TorrentConfig)
   186  	StartTorrentClient() error
   187  	Stop() error
   188  	IsReady() bool
   189  	GetCommunityChatsFilters(communityID types.HexBytes) ([]*transport.Filter, error)
   190  	GetCommunityChatsTopics(communityID types.HexBytes) ([]types.TopicType, error)
   191  	GetHistoryArchivePartitionStartTimestamp(communityID types.HexBytes) (uint64, error)
   192  	CreateAndSeedHistoryArchive(communityID types.HexBytes, topics []types.TopicType, startDate time.Time, endDate time.Time, partition time.Duration, encrypt bool) error
   193  	StartHistoryArchiveTasksInterval(community *Community, interval time.Duration)
   194  	StopHistoryArchiveTasksInterval(communityID types.HexBytes)
   195  	SeedHistoryArchiveTorrent(communityID types.HexBytes) error
   196  	UnseedHistoryArchiveTorrent(communityID types.HexBytes)
   197  	IsSeedingHistoryArchiveTorrent(communityID types.HexBytes) bool
   198  	GetHistoryArchiveDownloadTask(communityID string) *HistoryArchiveDownloadTask
   199  	AddHistoryArchiveDownloadTask(communityID string, task *HistoryArchiveDownloadTask)
   200  	DownloadHistoryArchivesByMagnetlink(communityID types.HexBytes, magnetlink string, cancelTask chan struct{}) (*HistoryArchiveDownloadTaskInfo, error)
   201  	TorrentFileExists(communityID string) bool
   202  }
   203  
   204  type ArchiveManagerConfig struct {
   205  	TorrentConfig *params.TorrentConfig
   206  	Logger        *zap.Logger
   207  	Persistence   *Persistence
   208  	Transport     *transport.Transport
   209  	Identity      *ecdsa.PrivateKey
   210  	Encryptor     *encryption.Protocol
   211  	Publisher     Publisher
   212  }
   213  
   214  func (t *HistoryArchiveDownloadTask) IsCancelled() bool {
   215  	t.m.RLock()
   216  	defer t.m.RUnlock()
   217  	return t.Cancelled
   218  }
   219  
   220  func (t *HistoryArchiveDownloadTask) Cancel() {
   221  	t.m.Lock()
   222  	defer t.m.Unlock()
   223  	t.Cancelled = true
   224  	close(t.CancelChan)
   225  }
   226  
   227  type membersReevaluationTask struct {
   228  	lastStartTime       time.Time
   229  	lastSuccessTime     time.Time
   230  	onDemandRequestTime time.Time
   231  	mutex               sync.Mutex
   232  }
   233  
   234  type managerOptions struct {
   235  	accountsManager        account.Manager
   236  	tokenManager           TokenManager
   237  	collectiblesManager    CollectiblesManager
   238  	walletConfig           *params.WalletConfig
   239  	communityTokensService CommunityTokensServiceInterface
   240  	permissionChecker      PermissionChecker
   241  
   242  	// allowForcingCommunityMembersReevaluation indicates whether we should allow forcing community members reevaluation.
   243  	// This will allow using `force` argument in ScheduleMembersReevaluation.
   244  	// Should only be used in tests.
   245  	allowForcingCommunityMembersReevaluation bool
   246  }
   247  
   248  type TokenManager interface {
   249  	GetBalancesByChain(ctx context.Context, accounts, tokens []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error)
   250  	GetCachedBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error)
   251  	FindOrCreateTokenByAddress(ctx context.Context, chainID uint64, address gethcommon.Address) *token.Token
   252  	GetAllChainIDs() ([]uint64, error)
   253  }
   254  
   255  type CollectibleContractData struct {
   256  	TotalSupply    *bigint.BigInt
   257  	Transferable   bool
   258  	RemoteBurnable bool
   259  	InfiniteSupply bool
   260  }
   261  
   262  type AssetContractData struct {
   263  	TotalSupply    *bigint.BigInt
   264  	InfiniteSupply bool
   265  }
   266  
   267  type CommunityTokensServiceInterface interface {
   268  	GetCollectibleContractData(chainID uint64, contractAddress string) (*CollectibleContractData, error)
   269  	SetSignerPubKey(ctx context.Context, chainID uint64, contractAddress string, txArgs transactions.SendTxArgs, password string, newSignerPubKey string) (string, error)
   270  	GetAssetContractData(chainID uint64, contractAddress string) (*AssetContractData, error)
   271  	SafeGetSignerPubKey(ctx context.Context, chainID uint64, communityID string) (string, error)
   272  	DeploymentSignatureDigest(chainID uint64, addressFrom string, communityID string) ([]byte, error)
   273  	ProcessCommunityTokenAction(message *protobuf.CommunityTokenAction) error
   274  }
   275  
   276  type DefaultTokenManager struct {
   277  	tokenManager   *token.Manager
   278  	networkManager network.ManagerInterface
   279  }
   280  
   281  func NewDefaultTokenManager(tm *token.Manager, nm network.ManagerInterface) *DefaultTokenManager {
   282  	return &DefaultTokenManager{tokenManager: tm, networkManager: nm}
   283  }
   284  
   285  type BalancesByChain = map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big
   286  
   287  func (m *DefaultTokenManager) GetAllChainIDs() ([]uint64, error) {
   288  	networks, err := m.networkManager.Get(false)
   289  	if err != nil {
   290  		return nil, err
   291  	}
   292  
   293  	areTestNetworksEnabled, err := m.networkManager.GetTestNetworksEnabled()
   294  	if err != nil {
   295  		return nil, err
   296  	}
   297  
   298  	chainIDs := make([]uint64, 0)
   299  	for _, network := range networks {
   300  		if areTestNetworksEnabled == network.IsTest {
   301  			chainIDs = append(chainIDs, network.ChainID)
   302  		}
   303  	}
   304  	return chainIDs, nil
   305  }
   306  
   307  type CollectiblesManager interface {
   308  	FetchBalancesByOwnerAndContractAddress(ctx context.Context, chainID walletcommon.ChainID, ownerAddress gethcommon.Address, contractAddresses []gethcommon.Address) (thirdparty.TokenBalancesPerContractAddress, error)
   309  	FetchCachedBalancesByOwnerAndContractAddress(ctx context.Context, chainID walletcommon.ChainID, ownerAddress gethcommon.Address, contractAddresses []gethcommon.Address) (thirdparty.TokenBalancesPerContractAddress, error)
   310  	GetCollectibleOwnership(id thirdparty.CollectibleUniqueID) ([]thirdparty.AccountBalance, error)
   311  	FetchCollectibleOwnersByContractAddress(ctx context.Context, chainID walletcommon.ChainID, contractAddress gethcommon.Address) (*thirdparty.CollectibleContractOwnership, error)
   312  }
   313  
   314  func (m *DefaultTokenManager) GetBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error) {
   315  	clients, err := m.tokenManager.RPCClient.EthClients(chainIDs)
   316  	if err != nil {
   317  		return nil, err
   318  	}
   319  
   320  	resp, err := m.tokenManager.GetBalancesByChain(context.Background(), clients, accounts, tokenAddresses)
   321  	return resp, err
   322  }
   323  
   324  func (m *DefaultTokenManager) GetCachedBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error) {
   325  	resp, err := m.tokenManager.GetCachedBalancesByChain(accounts, tokenAddresses, chainIDs)
   326  	if err != nil {
   327  		return resp, err
   328  	}
   329  
   330  	return resp, nil
   331  }
   332  
   333  func (m *DefaultTokenManager) FindOrCreateTokenByAddress(ctx context.Context, chainID uint64, address gethcommon.Address) *token.Token {
   334  	return m.tokenManager.FindOrCreateTokenByAddress(ctx, chainID, address)
   335  }
   336  
   337  type ManagerOption func(*managerOptions)
   338  
   339  func WithAccountManager(accountsManager account.Manager) ManagerOption {
   340  	return func(opts *managerOptions) {
   341  		opts.accountsManager = accountsManager
   342  	}
   343  }
   344  
   345  func WithPermissionChecker(permissionChecker PermissionChecker) ManagerOption {
   346  	return func(opts *managerOptions) {
   347  		opts.permissionChecker = permissionChecker
   348  	}
   349  }
   350  
   351  func WithCollectiblesManager(collectiblesManager CollectiblesManager) ManagerOption {
   352  	return func(opts *managerOptions) {
   353  		opts.collectiblesManager = collectiblesManager
   354  	}
   355  }
   356  
   357  func WithTokenManager(tokenManager TokenManager) ManagerOption {
   358  	return func(opts *managerOptions) {
   359  		opts.tokenManager = tokenManager
   360  	}
   361  }
   362  
   363  func WithWalletConfig(walletConfig *params.WalletConfig) ManagerOption {
   364  	return func(opts *managerOptions) {
   365  		opts.walletConfig = walletConfig
   366  	}
   367  }
   368  
   369  func WithCommunityTokensService(communityTokensService CommunityTokensServiceInterface) ManagerOption {
   370  	return func(opts *managerOptions) {
   371  		opts.communityTokensService = communityTokensService
   372  	}
   373  }
   374  
   375  func WithAllowForcingCommunityMembersReevaluation(enabled bool) ManagerOption {
   376  	return func(opts *managerOptions) {
   377  		opts.allowForcingCommunityMembersReevaluation = enabled
   378  	}
   379  }
   380  
   381  type OwnerVerifier interface {
   382  	SafeGetSignerPubKey(ctx context.Context, chainID uint64, communityID string) (string, error)
   383  }
   384  
   385  func NewManager(
   386  	identity *ecdsa.PrivateKey,
   387  	installationID string,
   388  	db *sql.DB,
   389  	encryptor *encryption.Protocol,
   390  	logger *zap.Logger,
   391  	ensverifier *ens.Verifier,
   392  	ownerVerifier OwnerVerifier,
   393  	transport *transport.Transport,
   394  	timesource common.TimeSource,
   395  	keyDistributor KeyDistributor,
   396  	mediaServer server.MediaServerInterface,
   397  	opts ...ManagerOption,
   398  ) (*Manager, error) {
   399  	if identity == nil {
   400  		return nil, errors.New("empty identity")
   401  	}
   402  
   403  	if timesource == nil {
   404  		return nil, errors.New("no timesource")
   405  	}
   406  
   407  	var err error
   408  	if logger == nil {
   409  		if logger, err = zap.NewDevelopment(); err != nil {
   410  			return nil, errors.Wrap(err, "failed to create a logger")
   411  		}
   412  	}
   413  
   414  	managerConfig := managerOptions{}
   415  	for _, opt := range opts {
   416  		opt(&managerConfig)
   417  	}
   418  
   419  	manager := &Manager{
   420  		logger:         logger,
   421  		encryptor:      encryptor,
   422  		identity:       identity,
   423  		installationID: installationID,
   424  		ownerVerifier:  ownerVerifier,
   425  		quit:           make(chan struct{}),
   426  		transport:      transport,
   427  		timesource:     timesource,
   428  		keyDistributor: keyDistributor,
   429  		communityLock:  NewCommunityLock(logger),
   430  		mediaServer:    mediaServer,
   431  	}
   432  
   433  	manager.persistence = &Persistence{
   434  		db:                      db,
   435  		recordBundleToCommunity: manager.dbRecordBundleToCommunity,
   436  	}
   437  
   438  	if managerConfig.accountsManager != nil {
   439  		manager.accountsManager = managerConfig.accountsManager
   440  	}
   441  
   442  	if managerConfig.collectiblesManager != nil {
   443  		manager.collectiblesManager = managerConfig.collectiblesManager
   444  	}
   445  
   446  	if managerConfig.tokenManager != nil {
   447  		manager.tokenManager = managerConfig.tokenManager
   448  	}
   449  
   450  	if managerConfig.walletConfig != nil {
   451  		manager.walletConfig = managerConfig.walletConfig
   452  	}
   453  
   454  	if managerConfig.communityTokensService != nil {
   455  		manager.communityTokensService = managerConfig.communityTokensService
   456  	}
   457  
   458  	if ensverifier != nil {
   459  		sub := ensverifier.Subscribe()
   460  		manager.ensSubscription = sub
   461  		manager.ensVerifier = ensverifier
   462  	}
   463  
   464  	if managerConfig.permissionChecker != nil {
   465  		manager.PermissionChecker = managerConfig.permissionChecker
   466  	} else {
   467  		manager.PermissionChecker = &DefaultPermissionChecker{
   468  			tokenManager:        manager.tokenManager,
   469  			collectiblesManager: manager.collectiblesManager,
   470  			logger:              logger,
   471  			ensVerifier:         ensverifier,
   472  		}
   473  	}
   474  
   475  	if managerConfig.allowForcingCommunityMembersReevaluation {
   476  		manager.logger.Warn("allowing forcing community members reevaluation, this should only be used in test environment")
   477  		manager.forceMembersReevaluation = make(map[string]chan struct{}, 10)
   478  	}
   479  
   480  	return manager, nil
   481  }
   482  
   483  type Subscription struct {
   484  	Community                                *Community
   485  	CreatingHistoryArchivesSignal            *signal.CreatingHistoryArchivesSignal
   486  	HistoryArchivesCreatedSignal             *signal.HistoryArchivesCreatedSignal
   487  	NoHistoryArchivesCreatedSignal           *signal.NoHistoryArchivesCreatedSignal
   488  	HistoryArchivesSeedingSignal             *signal.HistoryArchivesSeedingSignal
   489  	HistoryArchivesUnseededSignal            *signal.HistoryArchivesUnseededSignal
   490  	HistoryArchiveDownloadedSignal           *signal.HistoryArchiveDownloadedSignal
   491  	DownloadingHistoryArchivesStartedSignal  *signal.DownloadingHistoryArchivesStartedSignal
   492  	DownloadingHistoryArchivesFinishedSignal *signal.DownloadingHistoryArchivesFinishedSignal
   493  	ImportingHistoryArchiveMessagesSignal    *signal.ImportingHistoryArchiveMessagesSignal
   494  	CommunityEventsMessage                   *CommunityEventsMessage
   495  	AcceptedRequestsToJoin                   []types.HexBytes
   496  	RejectedRequestsToJoin                   []types.HexBytes
   497  	CommunityPrivilegedMemberSyncMessage     *CommunityPrivilegedMemberSyncMessage
   498  	TokenCommunityValidated                  *CommunityResponse
   499  }
   500  
   501  type CommunityResponse struct {
   502  	Community       *Community                             `json:"community"`
   503  	Changes         *CommunityChanges                      `json:"changes"`
   504  	RequestsToJoin  []*RequestToJoin                       `json:"requestsToJoin"`
   505  	FailedToDecrypt []*CommunityPrivateDataFailedToDecrypt `json:"-"`
   506  }
   507  
   508  func (m *Manager) SetMediaServer(mediaServer server.MediaServerInterface) {
   509  	m.mediaServer = mediaServer
   510  }
   511  
   512  func (m *Manager) Subscribe() chan *Subscription {
   513  	subscription := make(chan *Subscription, 100)
   514  	m.subscriptions = append(m.subscriptions, subscription)
   515  	return subscription
   516  }
   517  
   518  func (m *Manager) Start() error {
   519  	m.stopped = false
   520  	m.communityLock.Init()
   521  	if m.ensVerifier != nil {
   522  		m.runENSVerificationLoop()
   523  	}
   524  
   525  	if m.ownerVerifier != nil {
   526  		m.runOwnerVerificationLoop()
   527  	}
   528  
   529  	go func() {
   530  		_ = m.fillMissingCommunityTokens()
   531  	}()
   532  
   533  	return nil
   534  }
   535  
   536  func (m *Manager) runENSVerificationLoop() {
   537  	go func() {
   538  		for {
   539  			select {
   540  			case <-m.quit:
   541  				m.logger.Debug("quitting ens verification loop")
   542  				return
   543  			case records, more := <-m.ensSubscription:
   544  				if !more {
   545  					m.logger.Debug("no more ens records, quitting")
   546  					return
   547  				}
   548  				m.logger.Info("received records", zap.Any("records", records))
   549  			}
   550  		}
   551  	}()
   552  }
   553  
   554  // This function is mostly a way to fix any community that is missing tokens in its description
   555  func (m *Manager) fillMissingCommunityTokens() error {
   556  	controlledCommunities, err := m.Controlled()
   557  	if err != nil {
   558  		m.logger.Error("failed to retrieve orgs", zap.Error(err))
   559  		return err
   560  	}
   561  
   562  	unlock := func() {
   563  		for _, c := range controlledCommunities {
   564  			m.communityLock.Unlock(c.ID())
   565  		}
   566  	}
   567  	for _, c := range controlledCommunities {
   568  		m.communityLock.Lock(c.ID())
   569  	}
   570  	defer unlock()
   571  
   572  	for _, community := range controlledCommunities {
   573  		tokens, err := m.GetCommunityTokens(community.IDString())
   574  		if err != nil {
   575  			m.logger.Error("failed to retrieve community tokens", zap.Error(err))
   576  			return err
   577  		}
   578  
   579  		for _, token := range tokens {
   580  			if token.DeployState != community_token.Deployed {
   581  				continue
   582  			}
   583  			tokenMetadata := &protobuf.CommunityTokenMetadata{
   584  				ContractAddresses: map[uint64]string{uint64(token.ChainID): token.Address},
   585  				Description:       token.Description,
   586  				Image:             token.Base64Image,
   587  				Symbol:            token.Symbol,
   588  				TokenType:         token.TokenType,
   589  				Name:              token.Name,
   590  				Decimals:          uint32(token.Decimals),
   591  				Version:           token.Version,
   592  			}
   593  			modified, err := community.UpsertCommunityTokensMetadata(tokenMetadata)
   594  			if err != nil {
   595  				m.logger.Error("failed to add token metadata to the description", zap.Error(err))
   596  				return err
   597  			}
   598  			if modified {
   599  				err = m.saveAndPublish(community)
   600  				if err != nil {
   601  					m.logger.Error("failed to save the new community", zap.Error(err))
   602  					return err
   603  				}
   604  			}
   605  		}
   606  	}
   607  	return nil
   608  }
   609  
   610  // Only for testing
   611  func (m *Manager) CommunitiesToValidate() (map[string][]communityToValidate, error) { // nolint: golint
   612  	return m.persistence.getCommunitiesToValidate()
   613  }
   614  
   615  func (m *Manager) runOwnerVerificationLoop() {
   616  	m.logger.Info("starting owner verification loop")
   617  	go func() {
   618  		for {
   619  			select {
   620  			case <-m.quit:
   621  				m.logger.Debug("quitting owner verification loop")
   622  				return
   623  			case <-time.After(validateInterval):
   624  				// If ownerverifier is nil, we skip, this is useful for testing
   625  				if m.ownerVerifier == nil {
   626  					continue
   627  				}
   628  
   629  				communitiesToValidate, err := m.persistence.getCommunitiesToValidate()
   630  
   631  				if err != nil {
   632  					m.logger.Error("failed to fetch communities to validate", zap.Error(err))
   633  					continue
   634  				}
   635  				for id, communities := range communitiesToValidate {
   636  					m.logger.Info("validating communities", zap.String("id", id), zap.Int("count", len(communities)))
   637  
   638  					_, _ = m.validateCommunity(communities)
   639  				}
   640  			}
   641  		}
   642  	}()
   643  }
   644  
   645  func (m *Manager) ValidateCommunityByID(communityID types.HexBytes) (*CommunityResponse, error) {
   646  	communitiesToValidate, err := m.persistence.getCommunityToValidateByID(communityID)
   647  	if err != nil {
   648  		m.logger.Error("failed to validate community by ID", zap.String("id", communityID.String()), zap.Error(err))
   649  		return nil, err
   650  	}
   651  	return m.validateCommunity(communitiesToValidate)
   652  
   653  }
   654  
   655  func (m *Manager) validateCommunity(communityToValidateData []communityToValidate) (*CommunityResponse, error) {
   656  	for _, community := range communityToValidateData {
   657  		signer, description, err := UnwrapCommunityDescriptionMessage(community.payload)
   658  		if err != nil {
   659  			m.logger.Error("failed to unwrap community", zap.Error(err))
   660  			continue
   661  		}
   662  
   663  		chainID := CommunityDescriptionTokenOwnerChainID(description)
   664  		if chainID == 0 {
   665  			// This should not happen
   666  			m.logger.Error("chain id is 0, ignoring")
   667  			continue
   668  		}
   669  
   670  		m.logger.Info("validating community", zap.String("id", types.EncodeHex(community.id)), zap.String("signer", common.PubkeyToHex(signer)))
   671  
   672  		ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
   673  		defer cancel()
   674  
   675  		owner, err := m.ownerVerifier.SafeGetSignerPubKey(ctx, chainID, types.EncodeHex(community.id))
   676  		if err != nil {
   677  			m.logger.Error("failed to get owner", zap.Error(err))
   678  			continue
   679  		}
   680  
   681  		ownerPK, err := common.HexToPubkey(owner)
   682  		if err != nil {
   683  			m.logger.Error("failed to convert pk string to ecdsa", zap.Error(err))
   684  			continue
   685  		}
   686  
   687  		// TODO: handle shards
   688  		response, err := m.HandleCommunityDescriptionMessage(signer, description, community.payload, ownerPK, nil)
   689  		if err != nil {
   690  			m.logger.Error("failed to handle community", zap.Error(err))
   691  			err = m.persistence.DeleteCommunityToValidate(community.id, community.clock)
   692  			if err != nil {
   693  				m.logger.Error("failed to delete community to validate", zap.Error(err))
   694  			}
   695  			continue
   696  		}
   697  
   698  		if response != nil {
   699  
   700  			m.logger.Info("community validated", zap.String("id", types.EncodeHex(community.id)), zap.String("signer", common.PubkeyToHex(signer)))
   701  			m.publish(&Subscription{TokenCommunityValidated: response})
   702  			err := m.persistence.DeleteCommunitiesToValidateByCommunityID(community.id)
   703  			if err != nil {
   704  				m.logger.Error("failed to delete communities to validate", zap.Error(err))
   705  			}
   706  			return response, nil
   707  		}
   708  	}
   709  
   710  	return nil, nil
   711  }
   712  
   713  func (m *Manager) Stop() error {
   714  	m.stopped = true
   715  	close(m.quit)
   716  	for _, c := range m.subscriptions {
   717  		close(c)
   718  	}
   719  	return nil
   720  }
   721  
   722  func (m *Manager) publish(subscription *Subscription) {
   723  	if m.stopped {
   724  		return
   725  	}
   726  	for _, s := range m.subscriptions {
   727  		select {
   728  		case s <- subscription:
   729  		default:
   730  			m.logger.Warn("subscription channel full, dropping message")
   731  		}
   732  	}
   733  }
   734  
   735  func (m *Manager) All() ([]*Community, error) {
   736  	return m.persistence.AllCommunities(&m.identity.PublicKey)
   737  }
   738  
   739  type CommunityShard struct {
   740  	CommunityID string       `json:"communityID"`
   741  	Shard       *shard.Shard `json:"shard"`
   742  }
   743  
   744  type CuratedCommunities struct {
   745  	ContractCommunities         []string
   746  	ContractFeaturedCommunities []string
   747  }
   748  
   749  type KnownCommunitiesResponse struct {
   750  	ContractCommunities         []string              `json:"contractCommunities"`
   751  	ContractFeaturedCommunities []string              `json:"contractFeaturedCommunities"`
   752  	Descriptions                map[string]*Community `json:"communities"`
   753  	UnknownCommunities          []string              `json:"unknownCommunities"`
   754  }
   755  
   756  func (m *Manager) GetStoredDescriptionForCommunities(communityIDs []string) (*KnownCommunitiesResponse, error) {
   757  	response := &KnownCommunitiesResponse{
   758  		Descriptions: make(map[string]*Community),
   759  	}
   760  
   761  	for i := range communityIDs {
   762  		communityID := communityIDs[i]
   763  		communityIDBytes, err := types.DecodeHex(communityID)
   764  		if err != nil {
   765  			return nil, err
   766  		}
   767  
   768  		community, err := m.GetByID(types.HexBytes(communityIDBytes))
   769  		if err != nil && err != ErrOrgNotFound {
   770  			return nil, err
   771  		}
   772  
   773  		if community != nil {
   774  			response.Descriptions[community.IDString()] = community
   775  		} else {
   776  			response.UnknownCommunities = append(response.UnknownCommunities, communityID)
   777  		}
   778  
   779  		response.ContractCommunities = append(response.ContractCommunities, communityID)
   780  	}
   781  
   782  	return response, nil
   783  }
   784  
   785  func (m *Manager) Joined() ([]*Community, error) {
   786  	return m.persistence.JoinedCommunities(&m.identity.PublicKey)
   787  }
   788  
   789  func (m *Manager) Spectated() ([]*Community, error) {
   790  	return m.persistence.SpectatedCommunities(&m.identity.PublicKey)
   791  }
   792  
   793  func (m *Manager) CommunityUpdateLastOpenedAt(communityID types.HexBytes, timestamp int64) (*Community, error) {
   794  	m.communityLock.Lock(communityID)
   795  	defer m.communityLock.Unlock(communityID)
   796  
   797  	community, err := m.GetByID(communityID)
   798  	if err != nil {
   799  		return nil, err
   800  	}
   801  
   802  	err = m.persistence.UpdateLastOpenedAt(community.ID(), timestamp)
   803  	if err != nil {
   804  		return nil, err
   805  	}
   806  	community.UpdateLastOpenedAt(timestamp)
   807  	return community, nil
   808  }
   809  
   810  func (m *Manager) JoinedAndPendingCommunitiesWithRequests() ([]*Community, error) {
   811  	return m.persistence.JoinedAndPendingCommunitiesWithRequests(&m.identity.PublicKey)
   812  }
   813  
   814  func (m *Manager) DeletedCommunities() ([]*Community, error) {
   815  	return m.persistence.DeletedCommunities(&m.identity.PublicKey)
   816  }
   817  
   818  func (m *Manager) Controlled() ([]*Community, error) {
   819  	communities, err := m.persistence.CommunitiesWithPrivateKey(&m.identity.PublicKey)
   820  	if err != nil {
   821  		return nil, err
   822  	}
   823  
   824  	controlled := make([]*Community, 0, len(communities))
   825  
   826  	for _, c := range communities {
   827  		if c.IsControlNode() {
   828  			controlled = append(controlled, c)
   829  		}
   830  	}
   831  
   832  	return controlled, nil
   833  }
   834  
   835  // CreateCommunity takes a description, generates an ID for it, saves it and return it
   836  func (m *Manager) CreateCommunity(request *requests.CreateCommunity, publish bool) (*Community, error) {
   837  
   838  	description, err := request.ToCommunityDescription()
   839  	if err != nil {
   840  		return nil, err
   841  	}
   842  
   843  	description.Members = make(map[string]*protobuf.CommunityMember)
   844  	description.Members[common.PubkeyToHex(&m.identity.PublicKey)] = &protobuf.CommunityMember{Roles: []protobuf.CommunityMember_Roles{protobuf.CommunityMember_ROLE_OWNER}}
   845  
   846  	err = ValidateCommunityDescription(description)
   847  	if err != nil {
   848  		return nil, err
   849  	}
   850  
   851  	description.Clock = 1
   852  
   853  	key, err := crypto.GenerateKey()
   854  	if err != nil {
   855  		return nil, err
   856  	}
   857  
   858  	description.ID = types.EncodeHex(crypto.CompressPubkey(&key.PublicKey))
   859  
   860  	config := Config{
   861  		ID:                   &key.PublicKey,
   862  		PrivateKey:           key,
   863  		ControlNode:          &key.PublicKey,
   864  		ControlDevice:        true,
   865  		Logger:               m.logger,
   866  		Joined:               true,
   867  		JoinedAt:             time.Now().Unix(),
   868  		MemberIdentity:       m.identity,
   869  		CommunityDescription: description,
   870  		Shard:                nil,
   871  		LastOpenedAt:         0,
   872  	}
   873  
   874  	var descriptionEncryptor DescriptionEncryptor
   875  	if m.encryptor != nil {
   876  		descriptionEncryptor = m
   877  	}
   878  	community, err := New(config, m.timesource, descriptionEncryptor, m.mediaServer)
   879  	if err != nil {
   880  		return nil, err
   881  	}
   882  
   883  	// We join any community we create
   884  	community.Join()
   885  
   886  	err = m.persistence.SaveCommunity(community)
   887  	if err != nil {
   888  		return nil, err
   889  	}
   890  
   891  	// Save grant for own community
   892  	grant, err := community.BuildGrant(&m.identity.PublicKey, "")
   893  	if err != nil {
   894  		return nil, err
   895  	}
   896  	err = m.persistence.SaveCommunityGrant(community.IDString(), grant, uint64(time.Now().UnixMilli()))
   897  	if err != nil {
   898  		return nil, err
   899  	}
   900  
   901  	// Mark this device as the control node
   902  	syncControlNode := &protobuf.SyncCommunityControlNode{
   903  		Clock:          1,
   904  		InstallationId: m.installationID,
   905  	}
   906  	err = m.SaveSyncControlNode(community.ID(), syncControlNode)
   907  	if err != nil {
   908  		return nil, err
   909  	}
   910  
   911  	if publish {
   912  		m.publish(&Subscription{Community: community})
   913  	}
   914  
   915  	return community, nil
   916  }
   917  
   918  func (m *Manager) CreateCommunityTokenPermission(request *requests.CreateCommunityTokenPermission) (*Community, *CommunityChanges, error) {
   919  	m.communityLock.Lock(request.CommunityID)
   920  	defer m.communityLock.Unlock(request.CommunityID)
   921  
   922  	community, err := m.GetByID(request.CommunityID)
   923  	if err != nil {
   924  		return nil, nil, err
   925  	}
   926  
   927  	// ensure key is generated before marshaling,
   928  	// as it requires key to encrypt description
   929  	if community.IsControlNode() && m.encryptor != nil {
   930  		key, err := m.encryptor.GenerateHashRatchetKey(community.ID())
   931  		if err != nil {
   932  			return nil, nil, err
   933  		}
   934  		keyID, err := key.GetKeyID()
   935  		if err != nil {
   936  			return nil, nil, err
   937  		}
   938  		m.logger.Info("generate key for token", zap.String("group-id", types.Bytes2Hex(community.ID())), zap.String("key-id", types.Bytes2Hex(keyID)))
   939  	}
   940  
   941  	community, changes, err := m.createCommunityTokenPermission(request, community)
   942  	if err != nil {
   943  		return nil, nil, err
   944  	}
   945  
   946  	err = m.saveAndPublish(community)
   947  	if err != nil {
   948  		return nil, nil, err
   949  	}
   950  
   951  	return community, changes, nil
   952  }
   953  
   954  func (m *Manager) EditCommunityTokenPermission(request *requests.EditCommunityTokenPermission) (*Community, *CommunityChanges, error) {
   955  	m.communityLock.Lock(request.CommunityID)
   956  	defer m.communityLock.Unlock(request.CommunityID)
   957  
   958  	community, err := m.GetByID(request.CommunityID)
   959  	if err != nil {
   960  		return nil, nil, err
   961  	}
   962  
   963  	tokenPermission := request.ToCommunityTokenPermission()
   964  
   965  	changes, err := community.UpsertTokenPermission(&tokenPermission)
   966  	if err != nil {
   967  		return nil, nil, err
   968  	}
   969  
   970  	err = m.saveAndPublish(community)
   971  	if err != nil {
   972  		return nil, nil, err
   973  	}
   974  
   975  	return community, changes, nil
   976  }
   977  
   978  type reevaluateMemberRole struct {
   979  	old protobuf.CommunityMember_Roles
   980  	new protobuf.CommunityMember_Roles
   981  }
   982  
   983  func (rmr reevaluateMemberRole) hasChanged() bool {
   984  	return rmr.old != rmr.new
   985  }
   986  
   987  func (rmr reevaluateMemberRole) isPrivileged() bool {
   988  	return rmr.new != protobuf.CommunityMember_ROLE_NONE
   989  }
   990  
   991  func (rmr reevaluateMemberRole) hasChangedToPrivileged() bool {
   992  	return rmr.hasChanged() && rmr.old == protobuf.CommunityMember_ROLE_NONE
   993  }
   994  
   995  func (rmr reevaluateMemberRole) hasChangedPrivilegedRole() bool {
   996  	return (rmr.old == protobuf.CommunityMember_ROLE_ADMIN && rmr.new == protobuf.CommunityMember_ROLE_TOKEN_MASTER) ||
   997  		(rmr.old == protobuf.CommunityMember_ROLE_TOKEN_MASTER && rmr.new == protobuf.CommunityMember_ROLE_ADMIN)
   998  }
   999  
  1000  type reevaluateMembersResult struct {
  1001  	membersToRemove             map[string]struct{}
  1002  	membersRoles                map[string]*reevaluateMemberRole
  1003  	membersToRemoveFromChannels map[string]map[string]struct{}
  1004  	membersToAddToChannels      map[string]map[string]protobuf.CommunityMember_ChannelRole
  1005  }
  1006  
  1007  func (rmr *reevaluateMembersResult) newPrivilegedRoles() (map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey, error) {
  1008  	result := map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey{}
  1009  
  1010  	for memberKey, roles := range rmr.membersRoles {
  1011  		if roles.hasChangedToPrivileged() || roles.hasChangedPrivilegedRole() {
  1012  			memberPubKey, err := common.HexToPubkey(memberKey)
  1013  			if err != nil {
  1014  				return nil, err
  1015  			}
  1016  			if result[roles.new] == nil {
  1017  				result[roles.new] = []*ecdsa.PublicKey{}
  1018  			}
  1019  			result[roles.new] = append(result[roles.new], memberPubKey)
  1020  		}
  1021  	}
  1022  
  1023  	return result, nil
  1024  }
  1025  
  1026  // Fetch all owners for all collectibles.
  1027  func (m *Manager) fetchCollectiblesOwners(collectibles map[walletcommon.ChainID]map[gethcommon.Address]struct{}) (CollectiblesOwners, error) {
  1028  	if m.collectiblesManager == nil {
  1029  		return nil, errors.New("no collectibles manager")
  1030  	}
  1031  
  1032  	collectiblesOwners := make(CollectiblesOwners)
  1033  	for chainID, contractAddresses := range collectibles {
  1034  		collectiblesOwners[chainID] = make(map[gethcommon.Address]*thirdparty.CollectibleContractOwnership)
  1035  
  1036  		for contractAddress := range contractAddresses {
  1037  			ownership, err := m.collectiblesManager.FetchCollectibleOwnersByContractAddress(context.Background(), chainID, contractAddress)
  1038  			if err != nil {
  1039  				return nil, err
  1040  			}
  1041  			collectiblesOwners[chainID][contractAddress] = ownership
  1042  		}
  1043  	}
  1044  	return collectiblesOwners, nil
  1045  }
  1046  
  1047  // use it only for testing purposes
  1048  func (m *Manager) ReevaluateMembers(communityID types.HexBytes) (*Community, map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey, error) {
  1049  	return m.reevaluateMembers(communityID)
  1050  }
  1051  
  1052  // First, the community is read from the database,
  1053  // then the members are reevaluated, and only then
  1054  // the community is locked and changes are applied.
  1055  // NOTE: Changes made to the same community
  1056  // while reevaluation is ongoing are respected
  1057  // and do not affect the result of this function.
  1058  // If permissions are changed in the meantime,
  1059  // they will be accommodated with the next reevaluation.
  1060  func (m *Manager) reevaluateMembers(communityID types.HexBytes) (*Community, map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey, error) {
  1061  	community, err := m.GetByID(communityID)
  1062  	if err != nil {
  1063  		return nil, nil, err
  1064  	}
  1065  
  1066  	if !community.IsControlNode() {
  1067  		return nil, nil, ErrNotEnoughPermissions
  1068  	}
  1069  
  1070  	communityPermissionsPreParsedData, channelPermissionsPreParsedData := PreParsePermissionsData(community.tokenPermissions())
  1071  
  1072  	// Optimization: Fetch all collectibles owners before members iteration to avoid asking providers for the same collectibles.
  1073  	collectiblesOwners, err := m.fetchCollectiblesOwners(CollectibleAddressesFromPreParsedPermissionsData(communityPermissionsPreParsedData, channelPermissionsPreParsedData))
  1074  	if err != nil {
  1075  		return nil, nil, err
  1076  	}
  1077  
  1078  	result := &reevaluateMembersResult{
  1079  		membersToRemove:             map[string]struct{}{},
  1080  		membersRoles:                map[string]*reevaluateMemberRole{},
  1081  		membersToRemoveFromChannels: map[string]map[string]struct{}{},
  1082  		membersToAddToChannels:      map[string]map[string]protobuf.CommunityMember_ChannelRole{},
  1083  	}
  1084  
  1085  	membersAccounts, err := m.persistence.GetCommunityRequestsToJoinRevealedAddresses(community.ID())
  1086  	if err != nil {
  1087  		return nil, nil, err
  1088  	}
  1089  
  1090  	for memberKey := range community.Members() {
  1091  		memberPubKey, err := common.HexToPubkey(memberKey)
  1092  		if err != nil {
  1093  			return nil, nil, err
  1094  		}
  1095  
  1096  		if memberKey == common.PubkeyToHex(&m.identity.PublicKey) || community.IsMemberOwner(memberPubKey) {
  1097  			continue
  1098  		}
  1099  
  1100  		revealedAccount, memberHasWallet := membersAccounts[memberKey]
  1101  		if !memberHasWallet {
  1102  			result.membersToRemove[memberKey] = struct{}{}
  1103  			continue
  1104  		}
  1105  
  1106  		accountsAndChainIDs := revealedAccountsToAccountsAndChainIDsCombination(revealedAccount)
  1107  
  1108  		result.membersRoles[memberKey] = &reevaluateMemberRole{
  1109  			old: community.MemberRole(memberPubKey),
  1110  			new: protobuf.CommunityMember_ROLE_NONE,
  1111  		}
  1112  
  1113  		becomeTokenMasterPermissions := communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER]
  1114  		if becomeTokenMasterPermissions != nil {
  1115  			permissionResponse, err := m.PermissionChecker.CheckPermissionsWithPreFetchedData(becomeTokenMasterPermissions, accountsAndChainIDs, true, collectiblesOwners)
  1116  			if err != nil {
  1117  				return nil, nil, err
  1118  			}
  1119  
  1120  			if permissionResponse.Satisfied {
  1121  				result.membersRoles[memberKey].new = protobuf.CommunityMember_ROLE_TOKEN_MASTER
  1122  				// Skip further validation if user has TokenMaster permissions
  1123  				continue
  1124  			}
  1125  		}
  1126  
  1127  		becomeAdminPermissions := communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_ADMIN]
  1128  		if becomeAdminPermissions != nil {
  1129  			permissionResponse, err := m.PermissionChecker.CheckPermissionsWithPreFetchedData(becomeAdminPermissions, accountsAndChainIDs, true, collectiblesOwners)
  1130  			if err != nil {
  1131  				return nil, nil, err
  1132  			}
  1133  
  1134  			if permissionResponse.Satisfied {
  1135  				result.membersRoles[memberKey].new = protobuf.CommunityMember_ROLE_ADMIN
  1136  				// Skip further validation if user has Admin permissions
  1137  				continue
  1138  			}
  1139  		}
  1140  
  1141  		becomeMemberPermissions := communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_MEMBER]
  1142  		if becomeMemberPermissions != nil {
  1143  			permissionResponse, err := m.PermissionChecker.CheckPermissionsWithPreFetchedData(becomeMemberPermissions, accountsAndChainIDs, true, collectiblesOwners)
  1144  			if err != nil {
  1145  				return nil, nil, err
  1146  			}
  1147  
  1148  			if !permissionResponse.Satisfied {
  1149  				result.membersToRemove[memberKey] = struct{}{}
  1150  				// Skip channels validation if user has been removed
  1151  				continue
  1152  			}
  1153  		}
  1154  
  1155  		addToChannels, removeFromChannels, err := m.reevaluateMemberChannelsPermissions(community, memberPubKey, channelPermissionsPreParsedData, accountsAndChainIDs, collectiblesOwners)
  1156  		if err != nil {
  1157  			return nil, nil, err
  1158  		}
  1159  		result.membersToAddToChannels[memberKey] = addToChannels
  1160  		result.membersToRemoveFromChannels[memberKey] = removeFromChannels
  1161  	}
  1162  
  1163  	newPrivilegedRoles, err := result.newPrivilegedRoles()
  1164  	if err != nil {
  1165  		return nil, nil, err
  1166  	}
  1167  
  1168  	// Note: community itself may have changed in the meantime of permissions reevaluation.
  1169  	community, err = m.applyReevaluateMembersResult(communityID, result)
  1170  	if err != nil {
  1171  		return nil, nil, err
  1172  	}
  1173  
  1174  	return community, newPrivilegedRoles, m.saveAndPublish(community)
  1175  }
  1176  
  1177  // Apply results on the most up-to-date community.
  1178  func (m *Manager) applyReevaluateMembersResult(communityID types.HexBytes, result *reevaluateMembersResult) (*Community, error) {
  1179  	m.communityLock.Lock(communityID)
  1180  	defer m.communityLock.Unlock(communityID)
  1181  
  1182  	community, err := m.GetByID(communityID)
  1183  	if err != nil {
  1184  		return nil, err
  1185  	}
  1186  
  1187  	if !community.IsControlNode() {
  1188  		return nil, ErrNotEnoughPermissions
  1189  	}
  1190  
  1191  	// Remove members.
  1192  	for memberKey := range result.membersToRemove {
  1193  		memberPubKey, err := common.HexToPubkey(memberKey)
  1194  		if err != nil {
  1195  			return nil, err
  1196  		}
  1197  		_, err = community.RemoveUserFromOrg(memberPubKey)
  1198  		if err != nil {
  1199  			return nil, err
  1200  		}
  1201  	}
  1202  
  1203  	// Ensure members have proper roles.
  1204  	for memberKey, roles := range result.membersRoles {
  1205  		memberPubKey, err := common.HexToPubkey(memberKey)
  1206  		if err != nil {
  1207  			return nil, err
  1208  		}
  1209  
  1210  		if !community.HasMember(memberPubKey) {
  1211  			continue
  1212  		}
  1213  
  1214  		_, err = community.SetRoleToMember(memberPubKey, roles.new)
  1215  		if err != nil {
  1216  			return nil, err
  1217  		}
  1218  
  1219  		// Ensure privileged members can post in all chats.
  1220  		if roles.isPrivileged() {
  1221  			for channelID := range community.Chats() {
  1222  				_, err = community.AddMemberToChat(channelID, memberPubKey, []protobuf.CommunityMember_Roles{roles.new}, protobuf.CommunityMember_CHANNEL_ROLE_POSTER)
  1223  				if err != nil {
  1224  					return nil, err
  1225  				}
  1226  			}
  1227  		}
  1228  	}
  1229  
  1230  	// Remove members from channels.
  1231  	for memberKey, channels := range result.membersToRemoveFromChannels {
  1232  		memberPubKey, err := common.HexToPubkey(memberKey)
  1233  		if err != nil {
  1234  			return nil, err
  1235  		}
  1236  
  1237  		for channelID := range channels {
  1238  			_, err = community.RemoveUserFromChat(memberPubKey, channelID)
  1239  			if err != nil {
  1240  				return nil, err
  1241  			}
  1242  		}
  1243  	}
  1244  
  1245  	// Add unprivileged members to channels.
  1246  	for memberKey, channels := range result.membersToAddToChannels {
  1247  		memberPubKey, err := common.HexToPubkey(memberKey)
  1248  		if err != nil {
  1249  			return nil, err
  1250  		}
  1251  
  1252  		if !community.HasMember(memberPubKey) {
  1253  			continue
  1254  		}
  1255  
  1256  		for channelID, channelRole := range channels {
  1257  			_, err = community.AddMemberToChat(channelID, memberPubKey, []protobuf.CommunityMember_Roles{protobuf.CommunityMember_ROLE_NONE}, channelRole)
  1258  			if err != nil {
  1259  				return nil, err
  1260  			}
  1261  		}
  1262  	}
  1263  
  1264  	return community, nil
  1265  }
  1266  
  1267  func (m *Manager) reevaluateMemberChannelsPermissions(community *Community, memberPubKey *ecdsa.PublicKey,
  1268  	channelPermissionsPreParsedData map[string]*PreParsedCommunityPermissionsData, accountsAndChainIDs []*AccountChainIDsCombination, collectiblesOwners CollectiblesOwners) (map[string]protobuf.CommunityMember_ChannelRole, map[string]struct{}, error) {
  1269  
  1270  	addToChannels := map[string]protobuf.CommunityMember_ChannelRole{}
  1271  	removeFromChannels := map[string]struct{}{}
  1272  
  1273  	// check which permissions we satisfy and which not
  1274  	channelPermissionsCheckResult, err := m.checkChannelsPermissionsWithPreFetchedData(channelPermissionsPreParsedData, accountsAndChainIDs, true, collectiblesOwners)
  1275  	if err != nil {
  1276  		return nil, nil, err
  1277  	}
  1278  
  1279  	for channelID := range community.Chats() {
  1280  		channelPermissionsCheckResult, hasChannelPermission := channelPermissionsCheckResult[community.ChatID(channelID)]
  1281  
  1282  		// ensure member is added if channel has no permissions
  1283  		if !hasChannelPermission {
  1284  			addToChannels[channelID] = protobuf.CommunityMember_CHANNEL_ROLE_POSTER
  1285  			continue
  1286  		}
  1287  
  1288  		viewAndPostSatisfied, viewAndPostPermissionExists := channelPermissionsCheckResult[protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL]
  1289  		viewOnlySatisfied, viewOnlyPermissionExists := channelPermissionsCheckResult[protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL]
  1290  
  1291  		satisfied := false
  1292  		channelRole := protobuf.CommunityMember_CHANNEL_ROLE_VIEWER
  1293  		if viewAndPostPermissionExists && viewAndPostSatisfied {
  1294  			satisfied = viewAndPostSatisfied
  1295  			channelRole = protobuf.CommunityMember_CHANNEL_ROLE_POSTER
  1296  		} else if !satisfied && viewOnlyPermissionExists {
  1297  			satisfied = viewOnlySatisfied
  1298  		}
  1299  
  1300  		if satisfied {
  1301  			addToChannels[channelID] = channelRole
  1302  		} else {
  1303  			removeFromChannels[channelID] = struct{}{}
  1304  		}
  1305  	}
  1306  
  1307  	return addToChannels, removeFromChannels, nil
  1308  }
  1309  
  1310  func (m *Manager) checkChannelsPermissionsImpl(channelsPermissionsPreParsedData map[string]*PreParsedCommunityPermissionsData, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool, collectiblesOwners CollectiblesOwners) (map[string]map[protobuf.CommunityTokenPermission_Type]bool, error) {
  1311  	checkPermissions := func(channelsPermissionPreParsedData *PreParsedCommunityPermissionsData) (*CheckPermissionsResponse, error) {
  1312  		if collectiblesOwners != nil {
  1313  			return m.PermissionChecker.CheckPermissionsWithPreFetchedData(channelsPermissionPreParsedData, accountsAndChainIDs, true, collectiblesOwners)
  1314  		} else {
  1315  			return m.PermissionChecker.CheckPermissions(channelsPermissionPreParsedData, accountsAndChainIDs, true)
  1316  		}
  1317  	}
  1318  
  1319  	channelPermissionsCheckResult := make(map[string]map[protobuf.CommunityTokenPermission_Type]bool)
  1320  	for _, channelsPermissionPreParsedData := range channelsPermissionsPreParsedData {
  1321  		permissionResponse, err := checkPermissions(channelsPermissionPreParsedData)
  1322  		if err != nil {
  1323  			return channelPermissionsCheckResult, err
  1324  		}
  1325  		// Note: in `PreParsedCommunityPermissionsData` for channels there will be only one permission
  1326  		// no need to iterate over `Permissions`
  1327  		for _, chatId := range channelsPermissionPreParsedData.Permissions[0].ChatIds {
  1328  			if _, exists := channelPermissionsCheckResult[chatId]; !exists {
  1329  				channelPermissionsCheckResult[chatId] = make(map[protobuf.CommunityTokenPermission_Type]bool)
  1330  			}
  1331  			satisfied, exists := channelPermissionsCheckResult[chatId][channelsPermissionPreParsedData.Permissions[0].Type]
  1332  			if exists && satisfied {
  1333  				continue
  1334  			}
  1335  			channelPermissionsCheckResult[chatId][channelsPermissionPreParsedData.Permissions[0].Type] = permissionResponse.Satisfied
  1336  		}
  1337  	}
  1338  	return channelPermissionsCheckResult, nil
  1339  }
  1340  
  1341  func (m *Manager) checkChannelsPermissionsWithPreFetchedData(channelsPermissionsPreParsedData map[string]*PreParsedCommunityPermissionsData, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool, collectiblesOwners CollectiblesOwners) (map[string]map[protobuf.CommunityTokenPermission_Type]bool, error) {
  1342  	return m.checkChannelsPermissionsImpl(channelsPermissionsPreParsedData, accountsAndChainIDs, shortcircuit, collectiblesOwners)
  1343  }
  1344  
  1345  func (m *Manager) checkChannelsPermissions(channelsPermissionsPreParsedData map[string]*PreParsedCommunityPermissionsData, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool) (map[string]map[protobuf.CommunityTokenPermission_Type]bool, error) {
  1346  	return m.checkChannelsPermissionsImpl(channelsPermissionsPreParsedData, accountsAndChainIDs, shortcircuit, nil)
  1347  }
  1348  
  1349  func (m *Manager) StartMembersReevaluationLoop(communityID types.HexBytes, reevaluateOnStart bool) {
  1350  	go m.reevaluateMembersLoop(communityID, reevaluateOnStart)
  1351  }
  1352  
  1353  func (m *Manager) reevaluateMembersLoop(communityID types.HexBytes, reevaluateOnStart bool) {
  1354  
  1355  	if _, exists := m.membersReevaluationTasks.Load(communityID.String()); exists {
  1356  		return
  1357  	}
  1358  
  1359  	m.membersReevaluationTasks.Store(communityID.String(), &membersReevaluationTask{})
  1360  	defer m.membersReevaluationTasks.Delete(communityID.String())
  1361  
  1362  	var forceReevaluation chan struct{}
  1363  	if m.forceMembersReevaluation != nil {
  1364  		forceReevaluation = make(chan struct{}, 10)
  1365  		m.forceMembersReevaluation[communityID.String()] = forceReevaluation
  1366  	}
  1367  
  1368  	type criticalError struct {
  1369  		error
  1370  	}
  1371  
  1372  	shouldReevaluate := func(task *membersReevaluationTask, force bool) bool {
  1373  		task.mutex.Lock()
  1374  		defer task.mutex.Unlock()
  1375  
  1376  		// Ensure reevaluation is performed not more often than once per 5 minutes
  1377  		if !force && task.lastSuccessTime.After(time.Now().Add(-5*time.Minute)) {
  1378  			return false
  1379  		}
  1380  
  1381  		if !task.lastSuccessTime.Before(time.Now().Add(-memberPermissionsCheckInterval)) &&
  1382  			!task.lastStartTime.Before(task.onDemandRequestTime) {
  1383  			return false
  1384  		}
  1385  
  1386  		return true
  1387  	}
  1388  
  1389  	reevaluateMembers := func(force bool) (err error) {
  1390  		t, exists := m.membersReevaluationTasks.Load(communityID.String())
  1391  		if !exists {
  1392  			return criticalError{
  1393  				error: errors.New("missing task"),
  1394  			}
  1395  		}
  1396  		task, ok := t.(*membersReevaluationTask)
  1397  		if !ok {
  1398  			return criticalError{
  1399  				error: errors.New("invalid task type"),
  1400  			}
  1401  		}
  1402  
  1403  		if !shouldReevaluate(task, force) {
  1404  			return nil
  1405  		}
  1406  
  1407  		task.mutex.Lock()
  1408  		task.lastStartTime = time.Now()
  1409  		task.mutex.Unlock()
  1410  
  1411  		err = m.reevaluateCommunityMembersPermissions(communityID)
  1412  		if err != nil {
  1413  			if errors.Is(err, ErrOrgNotFound) {
  1414  				return criticalError{
  1415  					error: err,
  1416  				}
  1417  			}
  1418  			return err
  1419  		}
  1420  
  1421  		task.mutex.Lock()
  1422  		task.lastSuccessTime = time.Now()
  1423  		task.mutex.Unlock()
  1424  
  1425  		m.logger.Info("reevaluation finished", zap.String("communityID", communityID.String()), zap.Duration("elapsed", task.lastSuccessTime.Sub(task.lastStartTime)))
  1426  		return nil
  1427  	}
  1428  
  1429  	ticker := time.NewTicker(10 * time.Second)
  1430  	defer ticker.Stop()
  1431  
  1432  	reevaluate := reevaluateOnStart
  1433  	force := false
  1434  
  1435  	for {
  1436  		if reevaluate {
  1437  			err := reevaluateMembers(force)
  1438  			if err != nil {
  1439  				var criticalError *criticalError
  1440  				if errors.As(err, &criticalError) {
  1441  					return
  1442  				}
  1443  			}
  1444  		}
  1445  
  1446  		force = false
  1447  		reevaluate = false
  1448  
  1449  		select {
  1450  		case <-ticker.C:
  1451  			reevaluate = true
  1452  			continue
  1453  
  1454  		case <-forceReevaluation:
  1455  			reevaluate = true
  1456  			force = true
  1457  			continue
  1458  
  1459  		case <-m.quit:
  1460  			return
  1461  		}
  1462  	}
  1463  }
  1464  
  1465  func (m *Manager) ForceMembersReevaluation(communityID types.HexBytes) error {
  1466  	if m.forceMembersReevaluation == nil {
  1467  		return errors.New("forcing members reevaluation is not allowed")
  1468  	}
  1469  	return m.scheduleMembersReevaluation(communityID, true)
  1470  }
  1471  
  1472  func (m *Manager) ScheduleMembersReevaluation(communityID types.HexBytes) error {
  1473  	return m.scheduleMembersReevaluation(communityID, false)
  1474  }
  1475  
  1476  func (m *Manager) scheduleMembersReevaluation(communityID types.HexBytes, forceImmediateReevaluation bool) error {
  1477  	t, exists := m.membersReevaluationTasks.Load(communityID.String())
  1478  	if !exists {
  1479  		// No reevaluation task yet. We start the loop which will create it
  1480  		m.StartMembersReevaluationLoop(communityID, true)
  1481  		return nil
  1482  	}
  1483  
  1484  	task, ok := t.(*membersReevaluationTask)
  1485  	if !ok {
  1486  		return errors.New("invalid task type")
  1487  	}
  1488  	task.mutex.Lock()
  1489  	defer task.mutex.Unlock()
  1490  	task.onDemandRequestTime = time.Now()
  1491  
  1492  	if forceImmediateReevaluation {
  1493  		m.forceMembersReevaluation[communityID.String()] <- struct{}{}
  1494  	}
  1495  
  1496  	return nil
  1497  }
  1498  
  1499  func (m *Manager) DeleteCommunityTokenPermission(request *requests.DeleteCommunityTokenPermission) (*Community, *CommunityChanges, error) {
  1500  	m.communityLock.Lock(request.CommunityID)
  1501  	defer m.communityLock.Unlock(request.CommunityID)
  1502  
  1503  	community, err := m.GetByID(request.CommunityID)
  1504  	if err != nil {
  1505  		return nil, nil, err
  1506  	}
  1507  
  1508  	changes, err := community.DeleteTokenPermission(request.PermissionID)
  1509  	if err != nil {
  1510  		return nil, nil, err
  1511  	}
  1512  
  1513  	err = m.saveAndPublish(community)
  1514  	if err != nil {
  1515  		return nil, nil, err
  1516  	}
  1517  
  1518  	return community, changes, nil
  1519  }
  1520  
  1521  func (m *Manager) reevaluateCommunityMembersPermissions(communityID types.HexBytes) error {
  1522  	// Publish when the reevluation started since it can take a while
  1523  	signal.SendCommunityMemberReevaluationStarted(types.EncodeHex(communityID))
  1524  
  1525  	community, newPrivilegedMembers, err := m.reevaluateMembers(communityID)
  1526  
  1527  	// Publish the reevaluation ending, even if it errored
  1528  	// A possible improvement would be to pass the error here
  1529  	signal.SendCommunityMemberReevaluationEnded(types.EncodeHex(communityID))
  1530  
  1531  	if err != nil {
  1532  		return err
  1533  	}
  1534  
  1535  	return m.ShareRequestsToJoinWithPrivilegedMembers(community, newPrivilegedMembers)
  1536  }
  1537  
  1538  func (m *Manager) DeleteCommunity(id types.HexBytes) error {
  1539  	m.communityLock.Lock(id)
  1540  	defer m.communityLock.Unlock(id)
  1541  
  1542  	err := m.persistence.DeleteCommunity(id)
  1543  	if err != nil {
  1544  		return err
  1545  	}
  1546  	return m.persistence.DeleteCommunitySettings(id)
  1547  }
  1548  
  1549  func (m *Manager) updateShard(community *Community, shard *shard.Shard, clock uint64) error {
  1550  	community.config.Shard = shard
  1551  	if shard == nil {
  1552  		return m.persistence.DeleteCommunityShard(community.ID())
  1553  	}
  1554  
  1555  	return m.persistence.SaveCommunityShard(community.ID(), shard, clock)
  1556  }
  1557  
  1558  func (m *Manager) UpdateShard(community *Community, shard *shard.Shard, clock uint64) error {
  1559  	m.communityLock.Lock(community.ID())
  1560  	defer m.communityLock.Unlock(community.ID())
  1561  
  1562  	return m.updateShard(community, shard, clock)
  1563  }
  1564  
  1565  // SetShard assigns a shard to a community
  1566  func (m *Manager) SetShard(communityID types.HexBytes, shard *shard.Shard) (*Community, error) {
  1567  	m.communityLock.Lock(communityID)
  1568  	defer m.communityLock.Unlock(communityID)
  1569  
  1570  	community, err := m.GetByID(communityID)
  1571  	if err != nil {
  1572  		return nil, err
  1573  	}
  1574  
  1575  	community.increaseClock()
  1576  
  1577  	err = m.updateShard(community, shard, community.Clock())
  1578  	if err != nil {
  1579  		return nil, err
  1580  	}
  1581  
  1582  	err = m.saveAndPublish(community)
  1583  	if err != nil {
  1584  		return nil, err
  1585  	}
  1586  
  1587  	return community, nil
  1588  }
  1589  
  1590  func (m *Manager) UpdatePubsubTopicPrivateKey(topic string, privKey *ecdsa.PrivateKey) error {
  1591  	if privKey != nil {
  1592  		return m.transport.StorePubsubTopicKey(topic, privKey)
  1593  	}
  1594  
  1595  	return m.transport.RemovePubsubTopicKey(topic)
  1596  }
  1597  
  1598  // EditCommunity takes a description, updates the community with the description,
  1599  // saves it and returns it
  1600  func (m *Manager) EditCommunity(request *requests.EditCommunity) (*Community, error) {
  1601  	m.communityLock.Lock(request.CommunityID)
  1602  	defer m.communityLock.Unlock(request.CommunityID)
  1603  
  1604  	community, err := m.GetByID(request.CommunityID)
  1605  	if err != nil {
  1606  		return nil, err
  1607  	}
  1608  
  1609  	newDescription, err := request.ToCommunityDescription()
  1610  	if err != nil {
  1611  		return nil, fmt.Errorf("can't create community description: %v", err)
  1612  	}
  1613  
  1614  	// If permissions weren't explicitly set on original request, use existing ones
  1615  	if newDescription.Permissions.Access == protobuf.CommunityPermissions_UNKNOWN_ACCESS {
  1616  		newDescription.Permissions.Access = community.config.CommunityDescription.Permissions.Access
  1617  	}
  1618  	// Use existing images for the entries that were not updated
  1619  	// NOTE: This will NOT allow deletion of the community image; it will need to
  1620  	// be handled separately.
  1621  	for imageName := range community.config.CommunityDescription.Identity.Images {
  1622  		_, exists := newDescription.Identity.Images[imageName]
  1623  		if !exists {
  1624  			// If no image was set in ToCommunityDescription then Images is nil.
  1625  			if newDescription.Identity.Images == nil {
  1626  				newDescription.Identity.Images = make(map[string]*protobuf.IdentityImage)
  1627  			}
  1628  			newDescription.Identity.Images[imageName] = community.config.CommunityDescription.Identity.Images[imageName]
  1629  		}
  1630  	}
  1631  	// TODO: handle delete image (if needed)
  1632  
  1633  	err = ValidateCommunityDescription(newDescription)
  1634  	if err != nil {
  1635  		return nil, err
  1636  	}
  1637  
  1638  	if !(community.IsControlNode() || community.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_EDIT)) {
  1639  		return nil, ErrNotAuthorized
  1640  	}
  1641  
  1642  	// Edit the community values
  1643  	community.Edit(newDescription)
  1644  	if err != nil {
  1645  		return nil, err
  1646  	}
  1647  
  1648  	if community.IsControlNode() {
  1649  		community.increaseClock()
  1650  	} else {
  1651  		err := community.addNewCommunityEvent(community.ToCommunityEditCommunityEvent(newDescription))
  1652  		if err != nil {
  1653  			return nil, err
  1654  		}
  1655  	}
  1656  
  1657  	err = m.saveAndPublish(community)
  1658  	if err != nil {
  1659  		return nil, err
  1660  	}
  1661  
  1662  	return community, nil
  1663  }
  1664  
  1665  func (m *Manager) RemovePrivateKey(id types.HexBytes) (*Community, error) {
  1666  	m.communityLock.Lock(id)
  1667  	defer m.communityLock.Unlock(id)
  1668  
  1669  	community, err := m.GetByID(id)
  1670  	if err != nil {
  1671  		return community, err
  1672  	}
  1673  
  1674  	if !community.IsControlNode() {
  1675  		return community, ErrNotControlNode
  1676  	}
  1677  
  1678  	community.config.PrivateKey = nil
  1679  	err = m.persistence.SaveCommunity(community)
  1680  	if err != nil {
  1681  		return community, err
  1682  	}
  1683  	return community, nil
  1684  }
  1685  
  1686  func (m *Manager) ExportCommunity(id types.HexBytes) (*ecdsa.PrivateKey, error) {
  1687  	community, err := m.GetByID(id)
  1688  	if err != nil {
  1689  		return nil, err
  1690  	}
  1691  
  1692  	if !community.IsControlNode() {
  1693  		return nil, ErrNotControlNode
  1694  	}
  1695  
  1696  	return community.config.PrivateKey, nil
  1697  }
  1698  
  1699  func (m *Manager) ImportCommunity(key *ecdsa.PrivateKey, clock uint64) (*Community, error) {
  1700  	communityID := crypto.CompressPubkey(&key.PublicKey)
  1701  
  1702  	m.communityLock.Lock(communityID)
  1703  	defer m.communityLock.Unlock(communityID)
  1704  
  1705  	community, err := m.GetByID(communityID)
  1706  	if err != nil && err != ErrOrgNotFound {
  1707  		return nil, err
  1708  	}
  1709  
  1710  	if community == nil {
  1711  		createCommunityRequest := requests.CreateCommunity{
  1712  			Membership: protobuf.CommunityPermissions_MANUAL_ACCEPT,
  1713  			Name:       "unknown imported",
  1714  		}
  1715  
  1716  		description, err := createCommunityRequest.ToCommunityDescription()
  1717  		if err != nil {
  1718  			return nil, err
  1719  		}
  1720  
  1721  		err = ValidateCommunityDescription(description)
  1722  		if err != nil {
  1723  			return nil, err
  1724  		}
  1725  
  1726  		description.Clock = 1
  1727  		description.ID = types.EncodeHex(communityID)
  1728  
  1729  		config := Config{
  1730  			ID:                   &key.PublicKey,
  1731  			PrivateKey:           key,
  1732  			ControlNode:          &key.PublicKey,
  1733  			ControlDevice:        true,
  1734  			Logger:               m.logger,
  1735  			Joined:               true,
  1736  			JoinedAt:             time.Now().Unix(),
  1737  			MemberIdentity:       m.identity,
  1738  			CommunityDescription: description,
  1739  			LastOpenedAt:         0,
  1740  		}
  1741  
  1742  		var descriptionEncryptor DescriptionEncryptor
  1743  		if m.encryptor != nil {
  1744  			descriptionEncryptor = m
  1745  		}
  1746  		community, err = New(config, m.timesource, descriptionEncryptor, m.mediaServer)
  1747  		if err != nil {
  1748  			return nil, err
  1749  		}
  1750  	} else {
  1751  		community.config.PrivateKey = key
  1752  		community.config.ControlDevice = true
  1753  	}
  1754  
  1755  	community.Join()
  1756  	err = m.persistence.SaveCommunity(community)
  1757  	if err != nil {
  1758  		return nil, err
  1759  	}
  1760  
  1761  	// Save grant for own community
  1762  	grant, err := community.BuildGrant(&m.identity.PublicKey, "")
  1763  	if err != nil {
  1764  		return nil, err
  1765  	}
  1766  	err = m.persistence.SaveCommunityGrant(community.IDString(), grant, uint64(time.Now().UnixMilli()))
  1767  	if err != nil {
  1768  		return nil, err
  1769  	}
  1770  
  1771  	// Mark this device as the control node
  1772  	syncControlNode := &protobuf.SyncCommunityControlNode{
  1773  		Clock:          clock,
  1774  		InstallationId: m.installationID,
  1775  	}
  1776  	err = m.SaveSyncControlNode(community.ID(), syncControlNode)
  1777  	if err != nil {
  1778  		return nil, err
  1779  	}
  1780  
  1781  	return community, nil
  1782  }
  1783  
  1784  func (m *Manager) CreateChat(communityID types.HexBytes, chat *protobuf.CommunityChat, publish bool, thirdPartyID string) (*CommunityChanges, error) {
  1785  	m.communityLock.Lock(communityID)
  1786  	defer m.communityLock.Unlock(communityID)
  1787  
  1788  	community, err := m.GetByID(communityID)
  1789  	if err != nil {
  1790  		return nil, err
  1791  	}
  1792  	chatID := uuid.New().String()
  1793  	if thirdPartyID != "" {
  1794  		chatID = chatID + thirdPartyID
  1795  	}
  1796  
  1797  	changes, err := community.CreateChat(chatID, chat)
  1798  	if err != nil {
  1799  		return nil, err
  1800  	}
  1801  
  1802  	err = m.saveAndPublish(community)
  1803  	if err != nil {
  1804  		return nil, err
  1805  	}
  1806  
  1807  	return changes, nil
  1808  }
  1809  
  1810  func (m *Manager) EditChat(communityID types.HexBytes, chatID string, chat *protobuf.CommunityChat) (*Community, *CommunityChanges, error) {
  1811  	m.communityLock.Lock(communityID)
  1812  	defer m.communityLock.Unlock(communityID)
  1813  
  1814  	community, err := m.GetByID(communityID)
  1815  	if err != nil {
  1816  		return nil, nil, err
  1817  	}
  1818  
  1819  	// Remove communityID prefix from chatID if exists
  1820  	if strings.HasPrefix(chatID, communityID.String()) {
  1821  		chatID = strings.TrimPrefix(chatID, communityID.String())
  1822  	}
  1823  
  1824  	oldChat, err := community.GetChat(chatID)
  1825  	if err != nil {
  1826  		return nil, nil, err
  1827  	}
  1828  
  1829  	// We can't edit permissions and members with an Edit, so we set to what we had, otherwise they will be lost
  1830  	chat.Permissions = oldChat.Permissions
  1831  	chat.Members = oldChat.Members
  1832  
  1833  	changes, err := community.EditChat(chatID, chat)
  1834  	if err != nil {
  1835  		return nil, nil, err
  1836  	}
  1837  
  1838  	err = m.saveAndPublish(community)
  1839  	if err != nil {
  1840  		return nil, nil, err
  1841  	}
  1842  
  1843  	return community, changes, nil
  1844  }
  1845  
  1846  func (m *Manager) DeleteChat(communityID types.HexBytes, chatID string) (*Community, *CommunityChanges, error) {
  1847  	m.communityLock.Lock(communityID)
  1848  	defer m.communityLock.Unlock(communityID)
  1849  
  1850  	community, err := m.GetByID(communityID)
  1851  	if err != nil {
  1852  		return nil, nil, err
  1853  	}
  1854  
  1855  	// Check for channel permissions
  1856  	changes := community.emptyCommunityChanges()
  1857  	for tokenPermissionID, tokenPermission := range community.tokenPermissions() {
  1858  		chats := tokenPermission.ChatIdsAsMap()
  1859  		_, hasChat := chats[chatID]
  1860  		if !hasChat {
  1861  			continue
  1862  		}
  1863  
  1864  		if len(chats) == 1 {
  1865  			// Delete channel permission, if there is only one channel
  1866  			deletePermissionChanges, err := community.DeleteTokenPermission(tokenPermissionID)
  1867  			if err != nil {
  1868  				return nil, nil, err
  1869  			}
  1870  			changes.Merge(deletePermissionChanges)
  1871  		} else {
  1872  			// Remove the channel from the permission, if there are other channels
  1873  			delete(chats, chatID)
  1874  
  1875  			var chatIDs []string
  1876  			for chatID := range chats {
  1877  				chatIDs = append(chatIDs, chatID)
  1878  			}
  1879  			tokenPermission.ChatIds = chatIDs
  1880  
  1881  			updatePermissionChanges, err := community.UpsertTokenPermission(tokenPermission.CommunityTokenPermission)
  1882  			if err != nil {
  1883  				return nil, nil, err
  1884  			}
  1885  			changes.Merge(updatePermissionChanges)
  1886  		}
  1887  	}
  1888  
  1889  	// Remove communityID prefix from chatID if exists
  1890  	if strings.HasPrefix(chatID, communityID.String()) {
  1891  		chatID = strings.TrimPrefix(chatID, communityID.String())
  1892  	}
  1893  
  1894  	deleteChanges, err := community.DeleteChat(chatID)
  1895  	if err != nil {
  1896  		return nil, nil, err
  1897  	}
  1898  	changes.Merge(deleteChanges)
  1899  
  1900  	err = m.saveAndPublish(community)
  1901  	if err != nil {
  1902  		return nil, nil, err
  1903  	}
  1904  
  1905  	return community, changes, nil
  1906  }
  1907  
  1908  func (m *Manager) CreateCategory(request *requests.CreateCommunityCategory, publish bool) (*Community, *CommunityChanges, error) {
  1909  	m.communityLock.Lock(request.CommunityID)
  1910  	defer m.communityLock.Unlock(request.CommunityID)
  1911  
  1912  	community, err := m.GetByID(request.CommunityID)
  1913  	if err != nil {
  1914  		return nil, nil, err
  1915  	}
  1916  
  1917  	categoryID := uuid.New().String()
  1918  	if request.ThirdPartyID != "" {
  1919  		categoryID = categoryID + request.ThirdPartyID
  1920  	}
  1921  
  1922  	// Remove communityID prefix from chatID if exists
  1923  	for i, cid := range request.ChatIDs {
  1924  		if strings.HasPrefix(cid, request.CommunityID.String()) {
  1925  			request.ChatIDs[i] = strings.TrimPrefix(cid, request.CommunityID.String())
  1926  		}
  1927  	}
  1928  
  1929  	changes, err := community.CreateCategory(categoryID, request.CategoryName, request.ChatIDs)
  1930  	if err != nil {
  1931  		return nil, nil, err
  1932  	}
  1933  
  1934  	err = m.saveAndPublish(community)
  1935  	if err != nil {
  1936  		return nil, nil, err
  1937  	}
  1938  
  1939  	return community, changes, nil
  1940  }
  1941  
  1942  func (m *Manager) EditCategory(request *requests.EditCommunityCategory) (*Community, *CommunityChanges, error) {
  1943  	m.communityLock.Lock(request.CommunityID)
  1944  	defer m.communityLock.Unlock(request.CommunityID)
  1945  
  1946  	community, err := m.GetByID(request.CommunityID)
  1947  	if err != nil {
  1948  		return nil, nil, err
  1949  	}
  1950  
  1951  	// Remove communityID prefix from chatID if exists
  1952  	for i, cid := range request.ChatIDs {
  1953  		if strings.HasPrefix(cid, request.CommunityID.String()) {
  1954  			request.ChatIDs[i] = strings.TrimPrefix(cid, request.CommunityID.String())
  1955  		}
  1956  	}
  1957  
  1958  	changes, err := community.EditCategory(request.CategoryID, request.CategoryName, request.ChatIDs)
  1959  	if err != nil {
  1960  		return nil, nil, err
  1961  	}
  1962  
  1963  	err = m.saveAndPublish(community)
  1964  	if err != nil {
  1965  		return nil, nil, err
  1966  	}
  1967  
  1968  	return community, changes, nil
  1969  }
  1970  
  1971  func (m *Manager) EditChatFirstMessageTimestamp(communityID types.HexBytes, chatID string, timestamp uint32) (*Community, *CommunityChanges, error) {
  1972  	m.communityLock.Lock(communityID)
  1973  	defer m.communityLock.Unlock(communityID)
  1974  
  1975  	community, err := m.GetByID(communityID)
  1976  	if err != nil {
  1977  		return nil, nil, err
  1978  	}
  1979  
  1980  	// Remove communityID prefix from chatID if exists
  1981  	if strings.HasPrefix(chatID, communityID.String()) {
  1982  		chatID = strings.TrimPrefix(chatID, communityID.String())
  1983  	}
  1984  
  1985  	changes, err := community.UpdateChatFirstMessageTimestamp(chatID, timestamp)
  1986  	if err != nil {
  1987  		return nil, nil, err
  1988  	}
  1989  
  1990  	err = m.persistence.SaveCommunity(community)
  1991  	if err != nil {
  1992  		return nil, nil, err
  1993  	}
  1994  
  1995  	// Advertise changes
  1996  	m.publish(&Subscription{Community: community})
  1997  
  1998  	return community, changes, nil
  1999  }
  2000  
  2001  func (m *Manager) ReorderCategories(request *requests.ReorderCommunityCategories) (*Community, *CommunityChanges, error) {
  2002  	m.communityLock.Lock(request.CommunityID)
  2003  	defer m.communityLock.Unlock(request.CommunityID)
  2004  
  2005  	community, err := m.GetByID(request.CommunityID)
  2006  	if err != nil {
  2007  		return nil, nil, err
  2008  	}
  2009  
  2010  	changes, err := community.ReorderCategories(request.CategoryID, request.Position)
  2011  	if err != nil {
  2012  		return nil, nil, err
  2013  	}
  2014  
  2015  	err = m.saveAndPublish(community)
  2016  	if err != nil {
  2017  		return nil, nil, err
  2018  	}
  2019  
  2020  	return community, changes, nil
  2021  }
  2022  
  2023  func (m *Manager) ReorderChat(request *requests.ReorderCommunityChat) (*Community, *CommunityChanges, error) {
  2024  	m.communityLock.Lock(request.CommunityID)
  2025  	defer m.communityLock.Unlock(request.CommunityID)
  2026  
  2027  	community, err := m.GetByID(request.CommunityID)
  2028  	if err != nil {
  2029  		return nil, nil, err
  2030  	}
  2031  
  2032  	// Remove communityID prefix from chatID if exists
  2033  	if strings.HasPrefix(request.ChatID, request.CommunityID.String()) {
  2034  		request.ChatID = strings.TrimPrefix(request.ChatID, request.CommunityID.String())
  2035  	}
  2036  
  2037  	changes, err := community.ReorderChat(request.CategoryID, request.ChatID, request.Position)
  2038  	if err != nil {
  2039  		return nil, nil, err
  2040  	}
  2041  
  2042  	err = m.saveAndPublish(community)
  2043  	if err != nil {
  2044  		return nil, nil, err
  2045  	}
  2046  
  2047  	return community, changes, nil
  2048  }
  2049  
  2050  func (m *Manager) DeleteCategory(request *requests.DeleteCommunityCategory) (*Community, *CommunityChanges, error) {
  2051  	m.communityLock.Lock(request.CommunityID)
  2052  	defer m.communityLock.Unlock(request.CommunityID)
  2053  
  2054  	community, err := m.GetByID(request.CommunityID)
  2055  	if err != nil {
  2056  		return nil, nil, err
  2057  	}
  2058  
  2059  	changes, err := community.DeleteCategory(request.CategoryID)
  2060  	if err != nil {
  2061  		return nil, nil, err
  2062  	}
  2063  
  2064  	err = m.saveAndPublish(community)
  2065  	if err != nil {
  2066  		return nil, nil, err
  2067  	}
  2068  
  2069  	return changes.Community, changes, nil
  2070  }
  2071  
  2072  func (m *Manager) GenerateRequestsToJoinForAutoApprovalOnNewOwnership(communityID types.HexBytes, kickedMembers map[string]*protobuf.CommunityMember) ([]*RequestToJoin, error) {
  2073  	var requestsToJoin []*RequestToJoin
  2074  	clock := uint64(time.Now().Unix())
  2075  	for pubKeyStr := range kickedMembers {
  2076  		requestToJoin := &RequestToJoin{
  2077  			PublicKey:        pubKeyStr,
  2078  			Clock:            clock,
  2079  			CommunityID:      communityID,
  2080  			State:            RequestToJoinStateAwaitingAddresses,
  2081  			Our:              true,
  2082  			RevealedAccounts: make([]*protobuf.RevealedAccount, 0),
  2083  		}
  2084  
  2085  		requestToJoin.CalculateID()
  2086  
  2087  		requestsToJoin = append(requestsToJoin, requestToJoin)
  2088  	}
  2089  
  2090  	return requestsToJoin, m.persistence.SaveRequestsToJoin(requestsToJoin)
  2091  }
  2092  
  2093  func (m *Manager) Queue(signer *ecdsa.PublicKey, community *Community, clock uint64, payload []byte) error {
  2094  
  2095  	m.logger.Info("queuing community", zap.String("id", community.IDString()), zap.String("signer", common.PubkeyToHex(signer)))
  2096  
  2097  	communityToValidate := communityToValidate{
  2098  		id:         community.ID(),
  2099  		clock:      clock,
  2100  		payload:    payload,
  2101  		validateAt: uint64(time.Now().UnixNano()),
  2102  		signer:     crypto.CompressPubkey(signer),
  2103  	}
  2104  	err := m.persistence.SaveCommunityToValidate(communityToValidate)
  2105  	if err != nil {
  2106  		m.logger.Error("failed to save community", zap.Error(err))
  2107  		return err
  2108  	}
  2109  
  2110  	return nil
  2111  }
  2112  
  2113  func (m *Manager) HandleCommunityDescriptionMessage(signer *ecdsa.PublicKey, description *protobuf.CommunityDescription, payload []byte, verifiedOwner *ecdsa.PublicKey, communityShard *protobuf.Shard) (*CommunityResponse, error) {
  2114  	m.logger.Debug("HandleCommunityDescriptionMessage", zap.String("communityID", description.ID), zap.Uint64("clock", description.Clock))
  2115  
  2116  	if signer == nil {
  2117  		return nil, errors.New("signer can't be nil")
  2118  	}
  2119  
  2120  	var id []byte
  2121  	var err error
  2122  	if len(description.ID) != 0 {
  2123  		id, err = types.DecodeHex(description.ID)
  2124  		if err != nil {
  2125  			return nil, err
  2126  		}
  2127  	} else {
  2128  		// Backward compatibility
  2129  		id = crypto.CompressPubkey(signer)
  2130  	}
  2131  
  2132  	failedToDecrypt, processedDescription, err := m.preprocessDescription(id, description)
  2133  	if err != nil {
  2134  		return nil, err
  2135  	}
  2136  	m.communityLock.Lock(id)
  2137  	defer m.communityLock.Unlock(id)
  2138  	community, err := m.GetByID(id)
  2139  	if err != nil && err != ErrOrgNotFound {
  2140  		return nil, err
  2141  	}
  2142  
  2143  	// We don't process failed to decrypt if the whole metadata is encrypted
  2144  	// and we joined the community already
  2145  	if community != nil && community.Joined() && len(failedToDecrypt) != 0 && processedDescription != nil && len(processedDescription.Members) == 0 {
  2146  		return &CommunityResponse{FailedToDecrypt: failedToDecrypt}, nil
  2147  	}
  2148  
  2149  	// We should queue only if the community has a token owner, and the owner has been verified
  2150  	hasTokenOwnership := HasTokenOwnership(processedDescription)
  2151  	shouldQueue := hasTokenOwnership && verifiedOwner == nil
  2152  
  2153  	if community == nil {
  2154  		pubKey, err := crypto.DecompressPubkey(id)
  2155  		if err != nil {
  2156  			return nil, err
  2157  		}
  2158  		var cShard *shard.Shard
  2159  		if communityShard == nil {
  2160  			cShard = &shard.Shard{Cluster: shard.MainStatusShardCluster, Index: shard.DefaultShardIndex}
  2161  		} else {
  2162  			cShard = shard.FromProtobuff(communityShard)
  2163  		}
  2164  		config := Config{
  2165  			CommunityDescription:                processedDescription,
  2166  			Logger:                              m.logger,
  2167  			CommunityDescriptionProtocolMessage: payload,
  2168  			MemberIdentity:                      m.identity,
  2169  			ID:                                  pubKey,
  2170  			ControlNode:                         signer,
  2171  			Shard:                               cShard,
  2172  		}
  2173  
  2174  		var descriptionEncryptor DescriptionEncryptor
  2175  		if m.encryptor != nil {
  2176  			descriptionEncryptor = m
  2177  		}
  2178  		community, err = New(config, m.timesource, descriptionEncryptor, m.mediaServer)
  2179  		if err != nil {
  2180  			return nil, err
  2181  		}
  2182  
  2183  		// A new community, we need to check if we need to validate async.
  2184  		// That would be the case if it has a contract. We queue everything and process separately.
  2185  		if shouldQueue {
  2186  			return nil, m.Queue(signer, community, processedDescription.Clock, payload)
  2187  		}
  2188  	} else {
  2189  		// only queue if already known control node is different than the signer
  2190  		// and if the clock is greater
  2191  		shouldQueue = shouldQueue && !common.IsPubKeyEqual(community.ControlNode(), signer) &&
  2192  			community.config.CommunityDescription.Clock < processedDescription.Clock
  2193  		if shouldQueue {
  2194  			return nil, m.Queue(signer, community, processedDescription.Clock, payload)
  2195  		}
  2196  	}
  2197  
  2198  	if hasTokenOwnership && verifiedOwner != nil {
  2199  		// Override verified owner
  2200  		m.logger.Info("updating verified owner",
  2201  			zap.String("communityID", community.IDString()),
  2202  			zap.String("verifiedOwner", common.PubkeyToHex(verifiedOwner)),
  2203  			zap.String("signer", common.PubkeyToHex(signer)),
  2204  			zap.String("controlNode", common.PubkeyToHex(community.ControlNode())),
  2205  		)
  2206  
  2207  		// If we are not the verified owner anymore, drop the private key
  2208  		if !common.IsPubKeyEqual(verifiedOwner, &m.identity.PublicKey) {
  2209  			community.config.PrivateKey = nil
  2210  		}
  2211  
  2212  		// new control node will be set in the 'UpdateCommunityDescription'
  2213  		if !common.IsPubKeyEqual(verifiedOwner, signer) {
  2214  			return nil, ErrNotAuthorized
  2215  		}
  2216  	} else if !common.IsPubKeyEqual(community.ControlNode(), signer) {
  2217  		return nil, ErrNotAuthorized
  2218  	}
  2219  
  2220  	r, err := m.handleCommunityDescriptionMessageCommon(community, processedDescription, payload, verifiedOwner)
  2221  	if err != nil {
  2222  		return nil, err
  2223  	}
  2224  	r.FailedToDecrypt = failedToDecrypt
  2225  	return r, nil
  2226  }
  2227  
  2228  func (m *Manager) NewHashRatchetKeys(keys []*encryption.HashRatchetInfo) error {
  2229  	return m.persistence.InvalidateDecryptedCommunityCacheForKeys(keys)
  2230  }
  2231  
  2232  func (m *Manager) preprocessDescription(id types.HexBytes, description *protobuf.CommunityDescription) ([]*CommunityPrivateDataFailedToDecrypt, *protobuf.CommunityDescription, error) {
  2233  	decryptedCommunity, err := m.persistence.GetDecryptedCommunityDescription(id, description.Clock)
  2234  	if err != nil {
  2235  		return nil, nil, err
  2236  	}
  2237  	if decryptedCommunity != nil {
  2238  		return nil, decryptedCommunity, nil
  2239  	}
  2240  
  2241  	response, err := decryptDescription(id, m, description, m.logger)
  2242  	if err != nil {
  2243  		return response, description, err
  2244  	}
  2245  
  2246  	upgradeTokenPermissions(description)
  2247  
  2248  	// Workaround for https://github.com/status-im/status-desktop/issues/12188
  2249  	hydrateChannelsMembers(description)
  2250  
  2251  	return response, description, m.persistence.SaveDecryptedCommunityDescription(id, response, description)
  2252  }
  2253  
  2254  func (m *Manager) handleCommunityDescriptionMessageCommon(community *Community, description *protobuf.CommunityDescription, payload []byte, newControlNode *ecdsa.PublicKey) (*CommunityResponse, error) {
  2255  	prevClock := community.config.CommunityDescription.Clock
  2256  	prevResendAccountsClock := community.config.CommunityDescription.ResendAccountsClock
  2257  
  2258  	changes, err := community.UpdateCommunityDescription(description, payload, newControlNode)
  2259  	if err != nil {
  2260  		return nil, err
  2261  	}
  2262  
  2263  	if err = m.handleCommunityTokensMetadata(community); err != nil {
  2264  		return nil, err
  2265  	}
  2266  
  2267  	hasCommunityArchiveInfo, err := m.persistence.HasCommunityArchiveInfo(community.ID())
  2268  	if err != nil {
  2269  		return nil, err
  2270  	}
  2271  
  2272  	cdMagnetlinkClock := community.config.CommunityDescription.ArchiveMagnetlinkClock
  2273  	if !hasCommunityArchiveInfo {
  2274  		err = m.persistence.SaveCommunityArchiveInfo(community.ID(), cdMagnetlinkClock, 0)
  2275  		if err != nil {
  2276  			return nil, err
  2277  		}
  2278  	} else {
  2279  		magnetlinkClock, err := m.persistence.GetMagnetlinkMessageClock(community.ID())
  2280  		if err != nil {
  2281  			return nil, err
  2282  		}
  2283  		if cdMagnetlinkClock > magnetlinkClock {
  2284  			err = m.persistence.UpdateMagnetlinkMessageClock(community.ID(), cdMagnetlinkClock)
  2285  			if err != nil {
  2286  				return nil, err
  2287  			}
  2288  		}
  2289  	}
  2290  
  2291  	pkString := common.PubkeyToHex(&m.identity.PublicKey)
  2292  	if m.tokenManager != nil && description.CommunityTokensMetadata != nil && len(description.CommunityTokensMetadata) > 0 {
  2293  		for _, tokenMetadata := range description.CommunityTokensMetadata {
  2294  			if tokenMetadata.TokenType != protobuf.CommunityTokenType_ERC20 {
  2295  				continue
  2296  			}
  2297  
  2298  			for chainID, address := range tokenMetadata.ContractAddresses {
  2299  				_ = m.tokenManager.FindOrCreateTokenByAddress(context.Background(), chainID, gethcommon.HexToAddress(address))
  2300  			}
  2301  		}
  2302  	}
  2303  
  2304  	// If the community require membership, we set whether we should leave/join the community after a state change
  2305  	if community.ManualAccept() || community.AutoAccept() {
  2306  		if changes.HasNewMember(pkString) {
  2307  			hasPendingRequest, err := m.persistence.HasPendingRequestsToJoinForUserAndCommunity(pkString, changes.Community.ID())
  2308  			if err != nil {
  2309  				return nil, err
  2310  			}
  2311  			// If there's any pending request, we should join the community
  2312  			// automatically
  2313  			changes.ShouldMemberJoin = hasPendingRequest
  2314  		}
  2315  
  2316  		if changes.HasMemberLeft(pkString) && community.Joined() {
  2317  			softKick := !changes.IsMemberBanned(pkString) &&
  2318  				(changes.ControlNodeChanged != nil || prevResendAccountsClock < community.Description().ResendAccountsClock)
  2319  
  2320  			// If we joined previously the community, that means we have been kicked
  2321  			changes.MemberKicked = !softKick
  2322  			// soft kick previously joined member on community owner change or on ResendAccountsClock change
  2323  			changes.MemberSoftKicked = softKick
  2324  		}
  2325  	}
  2326  
  2327  	if description.Clock > prevClock {
  2328  		err = m.persistence.DeleteCommunityEvents(community.ID())
  2329  		if err != nil {
  2330  			return nil, err
  2331  		}
  2332  		community.config.EventsData = nil
  2333  	}
  2334  
  2335  	// Set Joined if we are part of the member list
  2336  	if !community.Joined() && community.hasMember(&m.identity.PublicKey) {
  2337  		changes.ShouldMemberJoin = true
  2338  	}
  2339  
  2340  	err = m.persistence.SaveCommunity(community)
  2341  	if err != nil {
  2342  		return nil, err
  2343  	}
  2344  
  2345  	// We mark our requests as completed, though maybe we should mark
  2346  	// any request for any user that has been added as completed
  2347  	if err := m.markRequestToJoinAsAccepted(&m.identity.PublicKey, community); err != nil {
  2348  		return nil, err
  2349  	}
  2350  	// Check if there's a change and we should be joining
  2351  
  2352  	return &CommunityResponse{
  2353  		Community: community,
  2354  		Changes:   changes,
  2355  	}, nil
  2356  }
  2357  
  2358  func (m *Manager) signEvents(community *Community) error {
  2359  	for i := range community.config.EventsData.Events {
  2360  		communityEvent := &community.config.EventsData.Events[i]
  2361  		if communityEvent.Signature == nil || len(communityEvent.Signature) == 0 {
  2362  			err := communityEvent.Sign(m.identity)
  2363  			if err != nil {
  2364  				return err
  2365  			}
  2366  		}
  2367  	}
  2368  	return nil
  2369  }
  2370  
  2371  func (m *Manager) HandleCommunityEventsMessage(signer *ecdsa.PublicKey, message *protobuf.CommunityEventsMessage) (*CommunityResponse, error) {
  2372  	if signer == nil {
  2373  		return nil, errors.New("signer can't be nil")
  2374  	}
  2375  
  2376  	eventsMessage, err := CommunityEventsMessageFromProtobuf(message)
  2377  	if err != nil {
  2378  		return nil, err
  2379  	}
  2380  
  2381  	m.communityLock.Lock(eventsMessage.CommunityID)
  2382  	defer m.communityLock.Unlock(eventsMessage.CommunityID)
  2383  
  2384  	community, err := m.GetByID(eventsMessage.CommunityID)
  2385  	if err != nil {
  2386  		return nil, err
  2387  	}
  2388  
  2389  	if !community.IsPrivilegedMember(signer) {
  2390  		return nil, errors.New("user has not permissions to send events")
  2391  	}
  2392  
  2393  	originCommunity := community.CreateDeepCopy()
  2394  
  2395  	var lastlyAppliedEvents map[string]uint64
  2396  	if community.IsControlNode() {
  2397  		lastlyAppliedEvents, err = m.persistence.GetAppliedCommunityEvents(community.ID())
  2398  		if err != nil {
  2399  			return nil, err
  2400  		}
  2401  	}
  2402  
  2403  	additionalCommunityResponse, err := m.handleCommunityEventsAndMetadata(community, eventsMessage, lastlyAppliedEvents)
  2404  	if err != nil {
  2405  		return nil, err
  2406  	}
  2407  
  2408  	// Control node applies events and publish updated CommunityDescription
  2409  	if community.IsControlNode() {
  2410  		appliedEvents := map[string]uint64{}
  2411  		if community.config.EventsData != nil {
  2412  			for _, event := range community.config.EventsData.Events {
  2413  				appliedEvents[event.EventTypeID()] = event.CommunityEventClock
  2414  			}
  2415  		}
  2416  		community.config.EventsData = nil // clear events, they are already applied
  2417  		community.increaseClock()
  2418  
  2419  		if m.keyDistributor != nil {
  2420  			encryptionKeyActions := EvaluateCommunityEncryptionKeyActions(originCommunity, community)
  2421  			err := m.keyDistributor.Generate(community, encryptionKeyActions)
  2422  			if err != nil {
  2423  				return nil, err
  2424  			}
  2425  		}
  2426  
  2427  		err = m.persistence.SaveCommunity(community)
  2428  		if err != nil {
  2429  			return nil, err
  2430  		}
  2431  
  2432  		err = m.persistence.UpsertAppliedCommunityEvents(community.ID(), appliedEvents)
  2433  		if err != nil {
  2434  			return nil, err
  2435  		}
  2436  
  2437  		m.publish(&Subscription{Community: community})
  2438  	} else {
  2439  		err = m.persistence.SaveCommunity(community)
  2440  		if err != nil {
  2441  			return nil, err
  2442  		}
  2443  		err := m.persistence.SaveCommunityEvents(community)
  2444  		if err != nil {
  2445  			return nil, err
  2446  		}
  2447  	}
  2448  
  2449  	return &CommunityResponse{
  2450  		Community:      community,
  2451  		Changes:        EvaluateCommunityChanges(originCommunity, community),
  2452  		RequestsToJoin: additionalCommunityResponse.RequestsToJoin,
  2453  	}, nil
  2454  }
  2455  
  2456  func (m *Manager) handleAdditionalAdminChanges(community *Community) (*CommunityResponse, error) {
  2457  	communityResponse := CommunityResponse{
  2458  		RequestsToJoin: make([]*RequestToJoin, 0),
  2459  	}
  2460  
  2461  	if !(community.IsControlNode() || community.HasPermissionToSendCommunityEvents()) {
  2462  		// we're a normal user/member node, so there's nothing for us to do here
  2463  		return &communityResponse, nil
  2464  	}
  2465  
  2466  	if community.config.EventsData == nil {
  2467  		return &communityResponse, nil
  2468  	}
  2469  
  2470  	handledMembers := map[string]struct{}{}
  2471  
  2472  	for i := len(community.config.EventsData.Events) - 1; i >= 0; i-- {
  2473  		communityEvent := &community.config.EventsData.Events[i]
  2474  		if _, handled := handledMembers[communityEvent.MemberToAction]; handled {
  2475  			continue
  2476  		}
  2477  		switch communityEvent.Type {
  2478  		case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT:
  2479  			handledMembers[communityEvent.MemberToAction] = struct{}{}
  2480  			requestsToJoin, err := m.handleCommunityEventRequestAccepted(community, communityEvent)
  2481  			if err != nil {
  2482  				return nil, err
  2483  			}
  2484  			if requestsToJoin != nil {
  2485  				communityResponse.RequestsToJoin = append(communityResponse.RequestsToJoin, requestsToJoin...)
  2486  			}
  2487  
  2488  		case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT:
  2489  			handledMembers[communityEvent.MemberToAction] = struct{}{}
  2490  			requestsToJoin, err := m.handleCommunityEventRequestRejected(community, communityEvent)
  2491  			if err != nil {
  2492  				return nil, err
  2493  			}
  2494  			if requestsToJoin != nil {
  2495  				communityResponse.RequestsToJoin = append(communityResponse.RequestsToJoin, requestsToJoin...)
  2496  			}
  2497  
  2498  		default:
  2499  		}
  2500  	}
  2501  	return &communityResponse, nil
  2502  }
  2503  
  2504  func (m *Manager) saveOrUpdateRequestToJoin(communityID types.HexBytes, requestToJoin *RequestToJoin) (bool, error) {
  2505  	updated := false
  2506  
  2507  	existingRequestToJoin, err := m.persistence.GetRequestToJoin(requestToJoin.ID)
  2508  	if err != nil && err != sql.ErrNoRows {
  2509  		return updated, err
  2510  	}
  2511  
  2512  	if existingRequestToJoin != nil {
  2513  		// node already knows about this request to join, so let's compare clocks
  2514  		// and update it if necessary
  2515  		if existingRequestToJoin.Clock <= requestToJoin.Clock {
  2516  			pk, err := common.HexToPubkey(existingRequestToJoin.PublicKey)
  2517  			if err != nil {
  2518  				return updated, err
  2519  			}
  2520  			err = m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), communityID, requestToJoin.State)
  2521  			if err != nil {
  2522  				return updated, err
  2523  			}
  2524  			updated = true
  2525  		}
  2526  	} else {
  2527  		err := m.persistence.SaveRequestToJoin(requestToJoin)
  2528  		if err != nil {
  2529  			return updated, err
  2530  		}
  2531  	}
  2532  
  2533  	return updated, nil
  2534  }
  2535  
  2536  func (m *Manager) handleCommunityEventRequestAccepted(community *Community, communityEvent *CommunityEvent) ([]*RequestToJoin, error) {
  2537  	acceptedRequestsToJoin := make([]types.HexBytes, 0)
  2538  
  2539  	requestsToJoin := make([]*RequestToJoin, 0)
  2540  
  2541  	signer := communityEvent.MemberToAction
  2542  	request := communityEvent.RequestToJoin
  2543  
  2544  	requestToJoin := &RequestToJoin{
  2545  		PublicKey:          signer,
  2546  		Clock:              request.Clock,
  2547  		ENSName:            request.EnsName,
  2548  		CommunityID:        request.CommunityId,
  2549  		State:              RequestToJoinStateAcceptedPending,
  2550  		CustomizationColor: multiaccountscommon.IDToColorFallbackToBlue(request.CustomizationColor),
  2551  	}
  2552  	requestToJoin.CalculateID()
  2553  
  2554  	existingRequestToJoin, err := m.persistence.GetRequestToJoin(requestToJoin.ID)
  2555  	if err != nil && err != sql.ErrNoRows {
  2556  		return nil, err
  2557  	}
  2558  
  2559  	if existingRequestToJoin != nil {
  2560  		alreadyProcessedByControlNode := existingRequestToJoin.State == RequestToJoinStateAccepted
  2561  		if alreadyProcessedByControlNode || existingRequestToJoin.State == RequestToJoinStateCanceled {
  2562  			return requestsToJoin, nil
  2563  		}
  2564  	}
  2565  
  2566  	requestUpdated, err := m.saveOrUpdateRequestToJoin(community.ID(), requestToJoin)
  2567  	if err != nil {
  2568  		return nil, err
  2569  	}
  2570  
  2571  	// If request to join exists in control node, add request to acceptedRequestsToJoin.
  2572  	// Otherwise keep the request as RequestToJoinStateAcceptedPending,
  2573  	// as privileged users don't have revealed addresses. This can happen if control node received
  2574  	// community event message before user request to join.
  2575  	if community.IsControlNode() && requestUpdated {
  2576  		acceptedRequestsToJoin = append(acceptedRequestsToJoin, requestToJoin.ID)
  2577  	}
  2578  
  2579  	requestsToJoin = append(requestsToJoin, requestToJoin)
  2580  
  2581  	if community.IsControlNode() {
  2582  		m.publish(&Subscription{AcceptedRequestsToJoin: acceptedRequestsToJoin})
  2583  	}
  2584  	return requestsToJoin, nil
  2585  }
  2586  
  2587  func (m *Manager) handleCommunityEventRequestRejected(community *Community, communityEvent *CommunityEvent) ([]*RequestToJoin, error) {
  2588  	rejectedRequestsToJoin := make([]types.HexBytes, 0)
  2589  
  2590  	requestsToJoin := make([]*RequestToJoin, 0)
  2591  
  2592  	signer := communityEvent.MemberToAction
  2593  	request := communityEvent.RequestToJoin
  2594  
  2595  	requestToJoin := &RequestToJoin{
  2596  		PublicKey:          signer,
  2597  		Clock:              request.Clock,
  2598  		ENSName:            request.EnsName,
  2599  		CommunityID:        request.CommunityId,
  2600  		State:              RequestToJoinStateDeclinedPending,
  2601  		CustomizationColor: multiaccountscommon.IDToColorFallbackToBlue(request.CustomizationColor),
  2602  	}
  2603  	requestToJoin.CalculateID()
  2604  
  2605  	existingRequestToJoin, err := m.persistence.GetRequestToJoin(requestToJoin.ID)
  2606  	if err != nil && err != sql.ErrNoRows {
  2607  		return nil, err
  2608  	}
  2609  
  2610  	if existingRequestToJoin != nil {
  2611  		alreadyProcessedByControlNode := existingRequestToJoin.State == RequestToJoinStateDeclined
  2612  		if alreadyProcessedByControlNode || existingRequestToJoin.State == RequestToJoinStateCanceled {
  2613  			return requestsToJoin, nil
  2614  		}
  2615  	}
  2616  
  2617  	requestUpdated, err := m.saveOrUpdateRequestToJoin(community.ID(), requestToJoin)
  2618  	if err != nil {
  2619  		return nil, err
  2620  	}
  2621  	// If request to join exists in control node, add request to rejectedRequestsToJoin.
  2622  	// Otherwise keep the request as RequestToJoinStateDeclinedPending,
  2623  	// as privileged users don't have revealed addresses. This can happen if control node received
  2624  	// community event message before user request to join.
  2625  	if community.IsControlNode() && requestUpdated {
  2626  		rejectedRequestsToJoin = append(rejectedRequestsToJoin, requestToJoin.ID)
  2627  	}
  2628  
  2629  	requestsToJoin = append(requestsToJoin, requestToJoin)
  2630  
  2631  	if community.IsControlNode() {
  2632  		m.publish(&Subscription{RejectedRequestsToJoin: rejectedRequestsToJoin})
  2633  	}
  2634  	return requestsToJoin, nil
  2635  }
  2636  
  2637  // markRequestToJoinAsAccepted marks all the pending requests to join as completed
  2638  // if we are members
  2639  func (m *Manager) markRequestToJoinAsAccepted(pk *ecdsa.PublicKey, community *Community) error {
  2640  	if community.HasMember(pk) {
  2641  		return m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), community.ID(), RequestToJoinStateAccepted)
  2642  	}
  2643  	return nil
  2644  }
  2645  
  2646  func (m *Manager) markRequestToJoinAsCanceled(pk *ecdsa.PublicKey, community *Community) error {
  2647  	return m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), community.ID(), RequestToJoinStateCanceled)
  2648  }
  2649  
  2650  func (m *Manager) markRequestToJoinAsAcceptedPending(pk *ecdsa.PublicKey, community *Community) error {
  2651  	return m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), community.ID(), RequestToJoinStateAcceptedPending)
  2652  }
  2653  
  2654  func (m *Manager) DeletePendingRequestToJoin(request *RequestToJoin) error {
  2655  	m.communityLock.Lock(request.CommunityID)
  2656  	defer m.communityLock.Unlock(request.CommunityID)
  2657  
  2658  	community, err := m.GetByID(request.CommunityID)
  2659  	if err != nil {
  2660  		return err
  2661  	}
  2662  
  2663  	err = m.persistence.DeletePendingRequestToJoin(request.ID)
  2664  	if err != nil {
  2665  		return err
  2666  	}
  2667  
  2668  	if community.IsControlNode() {
  2669  		err = m.saveAndPublish(community)
  2670  		if err != nil {
  2671  			return err
  2672  		}
  2673  	}
  2674  
  2675  	return nil
  2676  }
  2677  
  2678  func (m *Manager) UpdateClockInRequestToJoin(id types.HexBytes, clock uint64) error {
  2679  	return m.persistence.UpdateClockInRequestToJoin(id, clock)
  2680  }
  2681  
  2682  func (m *Manager) SetMuted(id types.HexBytes, muted bool) error {
  2683  	m.communityLock.Lock(id)
  2684  	defer m.communityLock.Unlock(id)
  2685  
  2686  	return m.persistence.SetMuted(id, muted)
  2687  }
  2688  
  2689  func (m *Manager) MuteCommunityTill(communityID []byte, muteTill time.Time) error {
  2690  	m.communityLock.Lock(communityID)
  2691  	defer m.communityLock.Unlock(communityID)
  2692  
  2693  	return m.persistence.MuteCommunityTill(communityID, muteTill)
  2694  }
  2695  func (m *Manager) CancelRequestToJoin(request *requests.CancelRequestToJoinCommunity) (*RequestToJoin, *Community, error) {
  2696  	dbRequest, err := m.persistence.GetRequestToJoin(request.ID)
  2697  	if err != nil {
  2698  		return nil, nil, err
  2699  	}
  2700  
  2701  	community, err := m.GetByID(dbRequest.CommunityID)
  2702  	if err != nil {
  2703  		return nil, nil, err
  2704  	}
  2705  
  2706  	pk, err := common.HexToPubkey(dbRequest.PublicKey)
  2707  	if err != nil {
  2708  		return nil, nil, err
  2709  	}
  2710  
  2711  	dbRequest.State = RequestToJoinStateCanceled
  2712  	if err := m.markRequestToJoinAsCanceled(pk, community); err != nil {
  2713  		return nil, nil, err
  2714  	}
  2715  
  2716  	return dbRequest, community, nil
  2717  }
  2718  
  2719  func (m *Manager) CheckPermissionToJoin(id []byte, addresses []gethcommon.Address) (*CheckPermissionToJoinResponse, error) {
  2720  	community, err := m.GetByID(id)
  2721  	if err != nil {
  2722  		return nil, err
  2723  	}
  2724  
  2725  	return m.PermissionChecker.CheckPermissionToJoin(community, addresses)
  2726  }
  2727  
  2728  func (m *Manager) accountsSatisfyPermissionsToJoin(
  2729  	communityPermissionsPreParsedData map[protobuf.CommunityTokenPermission_Type]*PreParsedCommunityPermissionsData,
  2730  	accountsAndChainIDs []*AccountChainIDsCombination) (bool, protobuf.CommunityMember_Roles, error) {
  2731  
  2732  	if m.accountsHasPrivilegedPermission(communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER], accountsAndChainIDs) {
  2733  		return true, protobuf.CommunityMember_ROLE_TOKEN_MASTER, nil
  2734  	}
  2735  	if m.accountsHasPrivilegedPermission(communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_ADMIN], accountsAndChainIDs) {
  2736  		return true, protobuf.CommunityMember_ROLE_ADMIN, nil
  2737  	}
  2738  
  2739  	preParsedBecomeMemberPermissions := communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_MEMBER]
  2740  	if preParsedBecomeMemberPermissions != nil {
  2741  		permissionResponse, err := m.PermissionChecker.CheckPermissions(preParsedBecomeMemberPermissions, accountsAndChainIDs, true)
  2742  		if err != nil {
  2743  			return false, protobuf.CommunityMember_ROLE_NONE, err
  2744  		}
  2745  
  2746  		return permissionResponse.Satisfied, protobuf.CommunityMember_ROLE_NONE, nil
  2747  	}
  2748  
  2749  	return true, protobuf.CommunityMember_ROLE_NONE, nil
  2750  }
  2751  
  2752  func (m *Manager) accountsSatisfyPermissionsToJoinChannels(
  2753  	community *Community,
  2754  	channelPermissionsPreParsedData map[string]*PreParsedCommunityPermissionsData,
  2755  	accountsAndChainIDs []*AccountChainIDsCombination) (map[string]*protobuf.CommunityChat, map[string]*protobuf.CommunityChat, error) {
  2756  
  2757  	viewChats := make(map[string]*protobuf.CommunityChat)
  2758  	viewAndPostChats := make(map[string]*protobuf.CommunityChat)
  2759  
  2760  	if len(channelPermissionsPreParsedData) == 0 {
  2761  		for channelID, channel := range community.config.CommunityDescription.Chats {
  2762  			viewAndPostChats[channelID] = channel
  2763  		}
  2764  
  2765  		return viewChats, viewAndPostChats, nil
  2766  	}
  2767  
  2768  	// check which permissions we satisfy and which not
  2769  	channelPermissionsCheckResult, err := m.checkChannelsPermissions(channelPermissionsPreParsedData, accountsAndChainIDs, true)
  2770  	if err != nil {
  2771  		m.logger.Warn("check channel permission failed: %v", zap.Error(err))
  2772  		return viewChats, viewAndPostChats, err
  2773  	}
  2774  
  2775  	for channelID, channel := range community.config.CommunityDescription.Chats {
  2776  		chatID := community.ChatID(channelID)
  2777  		channelPermissionsCheckResult, exists := channelPermissionsCheckResult[chatID]
  2778  
  2779  		if !exists {
  2780  			viewAndPostChats[channelID] = channel
  2781  			continue
  2782  		}
  2783  
  2784  		viewAndPostSatisfied, exists := channelPermissionsCheckResult[protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL]
  2785  		if exists && viewAndPostSatisfied {
  2786  			delete(viewChats, channelID)
  2787  			viewAndPostChats[channelID] = channel
  2788  			continue
  2789  		}
  2790  
  2791  		viewOnlySatisfied, exists := channelPermissionsCheckResult[protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL]
  2792  		if exists && viewOnlySatisfied {
  2793  			if _, exists := viewAndPostChats[channelID]; !exists {
  2794  				viewChats[channelID] = channel
  2795  			}
  2796  		}
  2797  	}
  2798  
  2799  	return viewChats, viewAndPostChats, nil
  2800  }
  2801  
  2802  func (m *Manager) AcceptRequestToJoin(dbRequest *RequestToJoin) (*Community, error) {
  2803  	m.communityLock.Lock(dbRequest.CommunityID)
  2804  	defer m.communityLock.Unlock(dbRequest.CommunityID)
  2805  
  2806  	pk, err := common.HexToPubkey(dbRequest.PublicKey)
  2807  	if err != nil {
  2808  		return nil, err
  2809  	}
  2810  
  2811  	community, err := m.GetByID(dbRequest.CommunityID)
  2812  	if err != nil {
  2813  		return nil, err
  2814  	}
  2815  
  2816  	if community.IsControlNode() {
  2817  		revealedAccounts, err := m.persistence.GetRequestToJoinRevealedAddresses(dbRequest.ID)
  2818  		if err != nil {
  2819  			return nil, err
  2820  		}
  2821  
  2822  		accountsAndChainIDs := revealedAccountsToAccountsAndChainIDsCombination(revealedAccounts)
  2823  
  2824  		communityPermissionsPreParsedData, channelPermissionsPreParsedData := PreParsePermissionsData(community.tokenPermissions())
  2825  
  2826  		permissionsSatisfied, role, err := m.accountsSatisfyPermissionsToJoin(communityPermissionsPreParsedData, accountsAndChainIDs)
  2827  		if err != nil {
  2828  			return nil, err
  2829  		}
  2830  
  2831  		if !permissionsSatisfied {
  2832  			return community, ErrNoPermissionToJoin
  2833  		}
  2834  
  2835  		memberRoles := []protobuf.CommunityMember_Roles{}
  2836  		if role != protobuf.CommunityMember_ROLE_NONE {
  2837  			memberRoles = []protobuf.CommunityMember_Roles{role}
  2838  		}
  2839  
  2840  		_, err = community.AddMember(pk, memberRoles, dbRequest.Clock)
  2841  		if err != nil {
  2842  			return nil, err
  2843  		}
  2844  
  2845  		viewChannels, postChannels, err := m.accountsSatisfyPermissionsToJoinChannels(community, channelPermissionsPreParsedData, accountsAndChainIDs)
  2846  		if err != nil {
  2847  			return nil, err
  2848  		}
  2849  
  2850  		for channelID := range viewChannels {
  2851  			_, err = community.AddMemberToChat(channelID, pk, memberRoles, protobuf.CommunityMember_CHANNEL_ROLE_VIEWER)
  2852  			if err != nil {
  2853  				return nil, err
  2854  			}
  2855  		}
  2856  
  2857  		for channelID := range postChannels {
  2858  			_, err = community.AddMemberToChat(channelID, pk, memberRoles, protobuf.CommunityMember_CHANNEL_ROLE_POSTER)
  2859  			if err != nil {
  2860  				return nil, err
  2861  			}
  2862  		}
  2863  
  2864  		dbRequest.State = RequestToJoinStateAccepted
  2865  		if err := m.markRequestToJoinAsAccepted(pk, community); err != nil {
  2866  			return nil, err
  2867  		}
  2868  
  2869  		dbRequest.RevealedAccounts = revealedAccounts
  2870  		if err = m.shareAcceptedRequestToJoinWithPrivilegedMembers(community, dbRequest); err != nil {
  2871  			return nil, err
  2872  		}
  2873  
  2874  		// if accepted member has a privilege role, share with him requests to join
  2875  		memberRole := community.MemberRole(pk)
  2876  		if memberRole == protobuf.CommunityMember_ROLE_OWNER || memberRole == protobuf.CommunityMember_ROLE_ADMIN ||
  2877  			memberRole == protobuf.CommunityMember_ROLE_TOKEN_MASTER {
  2878  
  2879  			newPrivilegedMember := make(map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey)
  2880  			newPrivilegedMember[memberRole] = []*ecdsa.PublicKey{pk}
  2881  			if err = m.ShareRequestsToJoinWithPrivilegedMembers(community, newPrivilegedMember); err != nil {
  2882  				return nil, err
  2883  			}
  2884  		}
  2885  	} else if community.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT) {
  2886  		err := community.addNewCommunityEvent(community.ToCommunityRequestToJoinAcceptCommunityEvent(dbRequest.PublicKey, dbRequest.ToCommunityRequestToJoinProtobuf()))
  2887  		if err != nil {
  2888  			return nil, err
  2889  		}
  2890  
  2891  		dbRequest.State = RequestToJoinStateAcceptedPending
  2892  		if err := m.markRequestToJoinAsAcceptedPending(pk, community); err != nil {
  2893  			return nil, err
  2894  		}
  2895  	} else {
  2896  		return nil, ErrNotAuthorized
  2897  	}
  2898  
  2899  	err = m.saveAndPublish(community)
  2900  	if err != nil {
  2901  		return nil, err
  2902  	}
  2903  
  2904  	return community, nil
  2905  }
  2906  
  2907  func (m *Manager) GetRequestToJoin(ID types.HexBytes) (*RequestToJoin, error) {
  2908  	return m.persistence.GetRequestToJoin(ID)
  2909  }
  2910  
  2911  func (m *Manager) DeclineRequestToJoin(dbRequest *RequestToJoin) (*Community, error) {
  2912  	m.communityLock.Lock(dbRequest.CommunityID)
  2913  	defer m.communityLock.Unlock(dbRequest.CommunityID)
  2914  
  2915  	community, err := m.GetByID(dbRequest.CommunityID)
  2916  	if err != nil {
  2917  		return nil, err
  2918  	}
  2919  
  2920  	adminEventCreated, err := community.DeclineRequestToJoin(dbRequest)
  2921  	if err != nil {
  2922  		return nil, err
  2923  	}
  2924  
  2925  	requestToJoinState := RequestToJoinStateDeclined
  2926  	if adminEventCreated {
  2927  		requestToJoinState = RequestToJoinStateDeclinedPending // can only be declined by control node
  2928  	}
  2929  
  2930  	dbRequest.State = requestToJoinState
  2931  	err = m.persistence.SetRequestToJoinState(dbRequest.PublicKey, dbRequest.CommunityID, requestToJoinState)
  2932  	if err != nil {
  2933  		return nil, err
  2934  	}
  2935  
  2936  	err = m.saveAndPublish(community)
  2937  	if err != nil {
  2938  		return nil, err
  2939  	}
  2940  
  2941  	return community, nil
  2942  }
  2943  
  2944  func (m *Manager) shouldUserRetainDeclined(signer *ecdsa.PublicKey, community *Community, requestClock uint64) (bool, error) {
  2945  	requestID := CalculateRequestID(common.PubkeyToHex(signer), types.HexBytes(community.IDString()))
  2946  	request, err := m.persistence.GetRequestToJoin(requestID)
  2947  	if err != nil {
  2948  		if err == sql.ErrNoRows {
  2949  			return false, nil
  2950  		}
  2951  		return false, err
  2952  	}
  2953  
  2954  	return request.ShouldRetainDeclined(requestClock)
  2955  }
  2956  
  2957  func (m *Manager) HandleCommunityCancelRequestToJoin(signer *ecdsa.PublicKey, request *protobuf.CommunityCancelRequestToJoin) (*RequestToJoin, error) {
  2958  	m.communityLock.Lock(request.CommunityId)
  2959  	defer m.communityLock.Unlock(request.CommunityId)
  2960  
  2961  	community, err := m.GetByID(request.CommunityId)
  2962  	if err != nil {
  2963  		return nil, err
  2964  	}
  2965  
  2966  	previousRequestToJoin, err := m.GetRequestToJoinByPkAndCommunityID(signer, community.ID())
  2967  	if err != nil {
  2968  		return nil, err
  2969  	}
  2970  
  2971  	if request.Clock <= previousRequestToJoin.Clock {
  2972  		return nil, ErrInvalidClock
  2973  	}
  2974  
  2975  	retainDeclined, err := m.shouldUserRetainDeclined(signer, community, request.Clock)
  2976  	if err != nil {
  2977  		return nil, err
  2978  	}
  2979  	if retainDeclined {
  2980  		return nil, ErrCommunityRequestAlreadyRejected
  2981  	}
  2982  
  2983  	err = m.markRequestToJoinAsCanceled(signer, community)
  2984  	if err != nil {
  2985  		return nil, err
  2986  	}
  2987  
  2988  	requestToJoin, err := m.persistence.GetRequestToJoinByPk(common.PubkeyToHex(signer), community.ID(), RequestToJoinStateCanceled)
  2989  	if err != nil {
  2990  		return nil, err
  2991  	}
  2992  
  2993  	if community.HasMember(signer) {
  2994  		_, err = community.RemoveUserFromOrg(signer)
  2995  		if err != nil {
  2996  			return nil, err
  2997  		}
  2998  
  2999  		err = m.saveAndPublish(community)
  3000  		if err != nil {
  3001  			return nil, err
  3002  		}
  3003  	}
  3004  
  3005  	return requestToJoin, nil
  3006  }
  3007  
  3008  func (m *Manager) HandleCommunityRequestToJoin(signer *ecdsa.PublicKey, receiver *ecdsa.PublicKey, request *protobuf.CommunityRequestToJoin) (*Community, *RequestToJoin, error) {
  3009  	community, err := m.GetByID(request.CommunityId)
  3010  	if err != nil {
  3011  		return nil, nil, err
  3012  	}
  3013  
  3014  	err = community.ValidateRequestToJoin(signer, request)
  3015  	if err != nil {
  3016  		return nil, nil, err
  3017  	}
  3018  
  3019  	nbPendingRequestsToJoin, err := m.persistence.GetNumberOfPendingRequestsToJoin(community.ID())
  3020  	if err != nil {
  3021  		return nil, nil, err
  3022  	}
  3023  	if nbPendingRequestsToJoin >= maxNbPendingRequestedMembers {
  3024  		return nil, nil, errors.New("max number of requests to join reached")
  3025  	}
  3026  
  3027  	requestToJoin := &RequestToJoin{
  3028  		PublicKey:          common.PubkeyToHex(signer),
  3029  		Clock:              request.Clock,
  3030  		ENSName:            request.EnsName,
  3031  		CommunityID:        request.CommunityId,
  3032  		State:              RequestToJoinStatePending,
  3033  		RevealedAccounts:   request.RevealedAccounts,
  3034  		CustomizationColor: multiaccountscommon.IDToColorFallbackToBlue(request.CustomizationColor),
  3035  	}
  3036  	requestToJoin.CalculateID()
  3037  
  3038  	existingRequestToJoin, err := m.persistence.GetRequestToJoin(requestToJoin.ID)
  3039  	if err != nil && err != sql.ErrNoRows {
  3040  		return nil, nil, err
  3041  	}
  3042  
  3043  	if existingRequestToJoin == nil {
  3044  		err = m.SaveRequestToJoin(requestToJoin)
  3045  		if err != nil {
  3046  			return nil, nil, err
  3047  		}
  3048  	} else {
  3049  		retainDeclined, err := existingRequestToJoin.ShouldRetainDeclined(request.Clock)
  3050  		if err != nil {
  3051  			return nil, nil, err
  3052  		}
  3053  		if retainDeclined {
  3054  			return nil, nil, ErrCommunityRequestAlreadyRejected
  3055  		}
  3056  
  3057  		switch existingRequestToJoin.State {
  3058  		case RequestToJoinStatePending, RequestToJoinStateDeclined, RequestToJoinStateCanceled:
  3059  			// Another request have been received, save request back to pending state
  3060  			err = m.SaveRequestToJoin(requestToJoin)
  3061  			if err != nil {
  3062  				return nil, nil, err
  3063  			}
  3064  		case RequestToJoinStateAccepted:
  3065  			// if member leaved the community and tries to request to join again
  3066  			if !community.HasMember(signer) {
  3067  				err = m.SaveRequestToJoin(requestToJoin)
  3068  				if err != nil {
  3069  					return nil, nil, err
  3070  				}
  3071  			}
  3072  		}
  3073  	}
  3074  
  3075  	if community.IsControlNode() {
  3076  		// verify if revealed addresses indeed belong to requester
  3077  		for _, revealedAccount := range request.RevealedAccounts {
  3078  			recoverParams := account.RecoverParams{
  3079  				Message:   types.EncodeHex(crypto.Keccak256(crypto.CompressPubkey(signer), community.ID(), requestToJoin.ID)),
  3080  				Signature: types.EncodeHex(revealedAccount.Signature),
  3081  			}
  3082  
  3083  			matching, err := m.accountsManager.CanRecover(recoverParams, types.HexToAddress(revealedAccount.Address))
  3084  			if err != nil {
  3085  				return nil, nil, err
  3086  			}
  3087  			if !matching {
  3088  				// if ownership of only one wallet address cannot be verified,
  3089  				// we mark the request as cancelled and stop
  3090  				requestToJoin.State = RequestToJoinStateDeclined
  3091  				return community, requestToJoin, nil
  3092  			}
  3093  		}
  3094  
  3095  		// Save revealed addresses + signatures so they can later be added
  3096  		// to the control node's local table of known revealed addresses
  3097  		err = m.persistence.SaveRequestToJoinRevealedAddresses(requestToJoin.ID, requestToJoin.RevealedAccounts)
  3098  		if err != nil {
  3099  			return nil, nil, err
  3100  		}
  3101  
  3102  		if existingRequestToJoin != nil {
  3103  			// request to join was already processed by privileged user
  3104  			// and waits to get confirmation for its decision
  3105  			if existingRequestToJoin.State == RequestToJoinStateDeclinedPending {
  3106  				requestToJoin.State = RequestToJoinStateDeclined
  3107  				return community, requestToJoin, nil
  3108  			} else if existingRequestToJoin.State == RequestToJoinStateAcceptedPending {
  3109  				requestToJoin.State = RequestToJoinStateAccepted
  3110  				return community, requestToJoin, nil
  3111  
  3112  			} else if existingRequestToJoin.State == RequestToJoinStateAwaitingAddresses {
  3113  				// community ownership changed, accept request automatically
  3114  				requestToJoin.State = RequestToJoinStateAccepted
  3115  				return community, requestToJoin, nil
  3116  			}
  3117  		}
  3118  
  3119  		// Check if we reached the limit, if we did, change the community setting to be On Request
  3120  		if community.AutoAccept() && community.MembersCount() >= maxNbMembers {
  3121  			community.EditPermissionAccess(protobuf.CommunityPermissions_MANUAL_ACCEPT)
  3122  			err = m.saveAndPublish(community)
  3123  			if err != nil {
  3124  				return nil, nil, err
  3125  			}
  3126  		}
  3127  
  3128  		// If user is already a member, then accept request automatically
  3129  		// It may happen when member removes itself from community and then tries to rejoin
  3130  		// More specifically, CommunityRequestToLeave may be delivered later than CommunityRequestToJoin, or not delivered at all
  3131  		acceptAutomatically := community.AutoAccept() || community.HasMember(signer)
  3132  		if acceptAutomatically {
  3133  			// Don't check permissions here,
  3134  			// it will be done further in the processing pipeline.
  3135  			requestToJoin.State = RequestToJoinStateAccepted
  3136  			return community, requestToJoin, nil
  3137  		}
  3138  	}
  3139  
  3140  	return community, requestToJoin, nil
  3141  }
  3142  
  3143  func (m *Manager) HandleCommunityEditSharedAddresses(signer *ecdsa.PublicKey, request *protobuf.CommunityEditSharedAddresses) error {
  3144  	m.communityLock.Lock(request.CommunityId)
  3145  	defer m.communityLock.Unlock(request.CommunityId)
  3146  
  3147  	community, err := m.GetByID(request.CommunityId)
  3148  	if err != nil {
  3149  		return err
  3150  	}
  3151  
  3152  	if !community.IsControlNode() {
  3153  		return ErrNotOwner
  3154  	}
  3155  
  3156  	publicKey := common.PubkeyToHex(signer)
  3157  
  3158  	if err := community.ValidateEditSharedAddresses(publicKey, request); err != nil {
  3159  		return err
  3160  	}
  3161  
  3162  	community.UpdateMemberLastUpdateClock(publicKey, request.Clock)
  3163  	// verify if revealed addresses indeed belong to requester
  3164  	for _, revealedAccount := range request.RevealedAccounts {
  3165  		recoverParams := account.RecoverParams{
  3166  			Message:   types.EncodeHex(crypto.Keccak256(crypto.CompressPubkey(signer), community.ID())),
  3167  			Signature: types.EncodeHex(revealedAccount.Signature),
  3168  		}
  3169  
  3170  		matching, err := m.accountsManager.CanRecover(recoverParams, types.HexToAddress(revealedAccount.Address))
  3171  		if err != nil {
  3172  			return err
  3173  		}
  3174  		if !matching {
  3175  			// if ownership of only one wallet address cannot be verified we stop
  3176  			return errors.New("wrong wallet address used")
  3177  		}
  3178  	}
  3179  
  3180  	err = m.handleCommunityEditSharedAddresses(publicKey, request.CommunityId, request.RevealedAccounts, request.Clock)
  3181  	if err != nil {
  3182  		return err
  3183  	}
  3184  
  3185  	err = m.persistence.SaveCommunity(community)
  3186  	if err != nil {
  3187  		return err
  3188  	}
  3189  
  3190  	if community.IsControlNode() {
  3191  		m.publish(&Subscription{Community: community})
  3192  	}
  3193  
  3194  	subscriptionMsg := &CommunityPrivilegedMemberSyncMessage{
  3195  		Receivers: community.GetTokenMasterMembers(),
  3196  		CommunityPrivilegedUserSyncMessage: &protobuf.CommunityPrivilegedUserSyncMessage{
  3197  			Type:        protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_MEMBER_EDIT_SHARED_ADDRESSES,
  3198  			CommunityId: community.ID(),
  3199  			SyncEditSharedAddresses: &protobuf.SyncCommunityEditSharedAddresses{
  3200  				PublicKey:         common.PubkeyToHex(signer),
  3201  				EditSharedAddress: request,
  3202  			},
  3203  		},
  3204  	}
  3205  
  3206  	m.publish(&Subscription{CommunityPrivilegedMemberSyncMessage: subscriptionMsg})
  3207  
  3208  	return nil
  3209  }
  3210  
  3211  func (m *Manager) handleCommunityEditSharedAddresses(publicKey string, communityID types.HexBytes, revealedAccounts []*protobuf.RevealedAccount, clock uint64) error {
  3212  	requestToJoinID := CalculateRequestID(publicKey, communityID)
  3213  	err := m.UpdateClockInRequestToJoin(requestToJoinID, clock)
  3214  	if err != nil {
  3215  		return err
  3216  	}
  3217  
  3218  	err = m.persistence.RemoveRequestToJoinRevealedAddresses(requestToJoinID)
  3219  	if err != nil {
  3220  		return err
  3221  	}
  3222  
  3223  	return m.persistence.SaveRequestToJoinRevealedAddresses(requestToJoinID, revealedAccounts)
  3224  }
  3225  
  3226  func calculateChainIDsSet(accountsAndChainIDs []*AccountChainIDsCombination, requirementsChainIDs map[uint64]bool) []uint64 {
  3227  
  3228  	revealedAccountsChainIDs := make([]uint64, 0)
  3229  	revealedAccountsChainIDsMap := make(map[uint64]bool)
  3230  
  3231  	// we want all chainIDs provided by revealed addresses that also exist
  3232  	// in the token requirements
  3233  	for _, accountAndChainIDs := range accountsAndChainIDs {
  3234  		for _, chainID := range accountAndChainIDs.ChainIDs {
  3235  			if requirementsChainIDs[chainID] && !revealedAccountsChainIDsMap[chainID] {
  3236  				revealedAccountsChainIDsMap[chainID] = true
  3237  				revealedAccountsChainIDs = append(revealedAccountsChainIDs, chainID)
  3238  			}
  3239  		}
  3240  	}
  3241  	return revealedAccountsChainIDs
  3242  }
  3243  
  3244  type CollectiblesByChain = map[uint64]map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress
  3245  
  3246  func (m *Manager) GetOwnedERC721Tokens(walletAddresses []gethcommon.Address, tokenRequirements map[uint64]map[string]*protobuf.TokenCriteria, chainIDs []uint64) (CollectiblesByChain, error) {
  3247  	if m.collectiblesManager == nil {
  3248  		return nil, errors.New("no collectibles manager")
  3249  	}
  3250  
  3251  	ctx := context.Background()
  3252  
  3253  	ownedERC721Tokens := make(CollectiblesByChain)
  3254  
  3255  	for chainID, erc721Tokens := range tokenRequirements {
  3256  
  3257  		skipChain := true
  3258  		for _, cID := range chainIDs {
  3259  			if chainID == cID {
  3260  				skipChain = false
  3261  			}
  3262  		}
  3263  
  3264  		if skipChain {
  3265  			continue
  3266  		}
  3267  
  3268  		contractAddresses := make([]gethcommon.Address, 0)
  3269  		for contractAddress := range erc721Tokens {
  3270  			contractAddresses = append(contractAddresses, gethcommon.HexToAddress(contractAddress))
  3271  		}
  3272  
  3273  		if _, exists := ownedERC721Tokens[chainID]; !exists {
  3274  			ownedERC721Tokens[chainID] = make(map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress)
  3275  		}
  3276  
  3277  		for _, owner := range walletAddresses {
  3278  			balances, err := m.collectiblesManager.FetchBalancesByOwnerAndContractAddress(ctx, walletcommon.ChainID(chainID), owner, contractAddresses)
  3279  			if err != nil {
  3280  				m.logger.Info("couldn't fetch owner assets", zap.Error(err))
  3281  				return nil, err
  3282  			}
  3283  			ownedERC721Tokens[chainID][owner] = balances
  3284  		}
  3285  	}
  3286  	return ownedERC721Tokens, nil
  3287  }
  3288  
  3289  func (m *Manager) CheckChannelPermissions(communityID types.HexBytes, chatID string, addresses []gethcommon.Address) (*CheckChannelPermissionsResponse, error) {
  3290  	m.communityLock.Lock(communityID)
  3291  	defer m.communityLock.Unlock(communityID)
  3292  
  3293  	community, err := m.GetByID(communityID)
  3294  	if err != nil {
  3295  		return nil, err
  3296  	}
  3297  
  3298  	if chatID == "" {
  3299  		return nil, errors.New(fmt.Sprintf("couldn't check channel permissions, invalid chat id: %s", chatID))
  3300  	}
  3301  
  3302  	viewOnlyPermissions := community.ChannelTokenPermissionsByType(chatID, protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL)
  3303  	viewAndPostPermissions := community.ChannelTokenPermissionsByType(chatID, protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL)
  3304  	viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
  3305  	viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
  3306  
  3307  	allChainIDs, err := m.tokenManager.GetAllChainIDs()
  3308  	if err != nil {
  3309  		return nil, err
  3310  	}
  3311  	accountsAndChainIDs := combineAddressesAndChainIDs(addresses, allChainIDs)
  3312  
  3313  	response, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountsAndChainIDs, false)
  3314  	if err != nil {
  3315  		return nil, err
  3316  	}
  3317  
  3318  	err = m.persistence.SaveCheckChannelPermissionResponse(communityID.String(), chatID, response)
  3319  	if err != nil {
  3320  		return nil, err
  3321  	}
  3322  	return response, nil
  3323  }
  3324  
  3325  type CheckChannelPermissionsResponse struct {
  3326  	ViewOnlyPermissions    *CheckChannelViewOnlyPermissionsResult    `json:"viewOnlyPermissions"`
  3327  	ViewAndPostPermissions *CheckChannelViewAndPostPermissionsResult `json:"viewAndPostPermissions"`
  3328  }
  3329  
  3330  type CheckChannelViewOnlyPermissionsResult struct {
  3331  	Satisfied   bool                                      `json:"satisfied"`
  3332  	Permissions map[string]*PermissionTokenCriteriaResult `json:"permissions"`
  3333  }
  3334  
  3335  type CheckChannelViewAndPostPermissionsResult struct {
  3336  	Satisfied   bool                                      `json:"satisfied"`
  3337  	Permissions map[string]*PermissionTokenCriteriaResult `json:"permissions"`
  3338  }
  3339  
  3340  func computeViewOnlySatisfied(hasViewOnlyPermissions bool, hasViewAndPostPermissions bool, checkedViewOnlySatisfied bool, checkedViewAndPostSatisified bool) bool {
  3341  	if (hasViewAndPostPermissions && !hasViewOnlyPermissions) || (hasViewOnlyPermissions && hasViewAndPostPermissions && checkedViewAndPostSatisified) {
  3342  		return checkedViewAndPostSatisified
  3343  	} else {
  3344  		return checkedViewOnlySatisfied
  3345  	}
  3346  }
  3347  
  3348  func computeViewAndPostSatisfied(hasViewOnlyPermissions bool, hasViewAndPostPermissions bool, checkedViewAndPostSatisified bool) bool {
  3349  	if hasViewOnlyPermissions && !hasViewAndPostPermissions {
  3350  		return false
  3351  	} else {
  3352  		return checkedViewAndPostSatisified
  3353  	}
  3354  }
  3355  
  3356  func (m *Manager) checkChannelPermissions(viewOnlyPreParsedPermissions *PreParsedCommunityPermissionsData, viewAndPostPreParsedPermissions *PreParsedCommunityPermissionsData, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool) (*CheckChannelPermissionsResponse, error) {
  3357  	viewOnlyPermissionsResponse, err := m.PermissionChecker.CheckPermissions(viewOnlyPreParsedPermissions, accountsAndChainIDs, shortcircuit)
  3358  	if err != nil {
  3359  		return nil, err
  3360  	}
  3361  
  3362  	viewAndPostPermissionsResponse, err := m.PermissionChecker.CheckPermissions(viewAndPostPreParsedPermissions, accountsAndChainIDs, shortcircuit)
  3363  	if err != nil {
  3364  		return nil, err
  3365  	}
  3366  
  3367  	hasViewOnlyPermissions := viewOnlyPreParsedPermissions != nil
  3368  	hasViewAndPostPermissions := viewAndPostPreParsedPermissions != nil
  3369  
  3370  	return computeCheckChannelPermissionsResponse(hasViewOnlyPermissions, hasViewAndPostPermissions,
  3371  			viewOnlyPermissionsResponse, viewAndPostPermissionsResponse),
  3372  		nil
  3373  }
  3374  
  3375  func computeCheckChannelPermissionsResponse(hasViewOnlyPermissions bool, hasViewAndPostPermissions bool,
  3376  	viewOnlyPermissionsResponse *CheckPermissionsResponse, viewAndPostPermissionsResponse *CheckPermissionsResponse) *CheckChannelPermissionsResponse {
  3377  
  3378  	response := &CheckChannelPermissionsResponse{
  3379  		ViewOnlyPermissions: &CheckChannelViewOnlyPermissionsResult{
  3380  			Satisfied:   false,
  3381  			Permissions: make(map[string]*PermissionTokenCriteriaResult),
  3382  		},
  3383  		ViewAndPostPermissions: &CheckChannelViewAndPostPermissionsResult{
  3384  			Satisfied:   false,
  3385  			Permissions: make(map[string]*PermissionTokenCriteriaResult),
  3386  		},
  3387  	}
  3388  
  3389  	viewOnlySatisfied := !hasViewOnlyPermissions || viewOnlyPermissionsResponse.Satisfied
  3390  	viewAndPostSatisfied := !hasViewAndPostPermissions || viewAndPostPermissionsResponse.Satisfied
  3391  
  3392  	response.ViewOnlyPermissions.Satisfied = computeViewOnlySatisfied(hasViewOnlyPermissions, hasViewAndPostPermissions,
  3393  		viewOnlySatisfied, viewAndPostSatisfied)
  3394  	if viewOnlyPermissionsResponse != nil {
  3395  		response.ViewOnlyPermissions.Permissions = viewOnlyPermissionsResponse.Permissions
  3396  	}
  3397  
  3398  	response.ViewAndPostPermissions.Satisfied = computeViewAndPostSatisfied(hasViewOnlyPermissions, hasViewAndPostPermissions,
  3399  		viewAndPostSatisfied)
  3400  
  3401  	if viewAndPostPermissionsResponse != nil {
  3402  		response.ViewAndPostPermissions.Permissions = viewAndPostPermissionsResponse.Permissions
  3403  	}
  3404  
  3405  	return response
  3406  }
  3407  
  3408  func (m *Manager) CheckAllChannelsPermissions(communityID types.HexBytes, addresses []gethcommon.Address) (*CheckAllChannelsPermissionsResponse, error) {
  3409  
  3410  	community, err := m.GetByID(communityID)
  3411  	if err != nil {
  3412  		return nil, err
  3413  	}
  3414  	channels := community.Chats()
  3415  
  3416  	allChainIDs, err := m.tokenManager.GetAllChainIDs()
  3417  	if err != nil {
  3418  		return nil, err
  3419  	}
  3420  	accountsAndChainIDs := combineAddressesAndChainIDs(addresses, allChainIDs)
  3421  
  3422  	_, channelsPermissionsPreParsedData := PreParsePermissionsData(community.tokenPermissions())
  3423  
  3424  	channelPermissionsCheckResult := make(map[string]map[protobuf.CommunityTokenPermission_Type]*CheckPermissionsResponse)
  3425  
  3426  	for permissionId, channelsPermissionPreParsedData := range channelsPermissionsPreParsedData {
  3427  		permissionResponse, err := m.PermissionChecker.CheckPermissions(channelsPermissionPreParsedData, accountsAndChainIDs, false)
  3428  		if err != nil {
  3429  			return nil, err
  3430  		}
  3431  
  3432  		// Note: in `PreParsedCommunityPermissionsData` for channels there will be only one permission for channels
  3433  		for _, chatId := range channelsPermissionPreParsedData.Permissions[0].ChatIds {
  3434  			if _, exists := channelPermissionsCheckResult[chatId]; !exists {
  3435  				channelPermissionsCheckResult[chatId] = make(map[protobuf.CommunityTokenPermission_Type]*CheckPermissionsResponse)
  3436  			}
  3437  			storedPermissionResponse, exists := channelPermissionsCheckResult[chatId][channelsPermissionPreParsedData.Permissions[0].Type]
  3438  			if !exists {
  3439  				channelPermissionsCheckResult[chatId][channelsPermissionPreParsedData.Permissions[0].Type] =
  3440  					permissionResponse
  3441  			} else {
  3442  				channelPermissionsCheckResult[chatId][channelsPermissionPreParsedData.Permissions[0].Type].Permissions[permissionId] =
  3443  					permissionResponse.Permissions[permissionId]
  3444  				channelPermissionsCheckResult[chatId][channelsPermissionPreParsedData.Permissions[0].Type].Satisfied =
  3445  					storedPermissionResponse.Satisfied || permissionResponse.Satisfied
  3446  			}
  3447  		}
  3448  	}
  3449  
  3450  	response := &CheckAllChannelsPermissionsResponse{
  3451  		Channels: make(map[string]*CheckChannelPermissionsResponse),
  3452  	}
  3453  
  3454  	for channelID := range channels {
  3455  		chatId := community.ChatID(channelID)
  3456  
  3457  		channelCheckPermissionsResponse, exists := channelPermissionsCheckResult[chatId]
  3458  
  3459  		var channelPermissionsResponse *CheckChannelPermissionsResponse
  3460  		if !exists {
  3461  			channelPermissionsResponse = computeCheckChannelPermissionsResponse(false, false, nil, nil)
  3462  		} else {
  3463  			viewPermissionsResponse, viewExists := channelCheckPermissionsResponse[protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL]
  3464  			postPermissionsResponse, postExists := channelCheckPermissionsResponse[protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL]
  3465  			channelPermissionsResponse = computeCheckChannelPermissionsResponse(viewExists, postExists, viewPermissionsResponse, postPermissionsResponse)
  3466  		}
  3467  
  3468  		err = m.persistence.SaveCheckChannelPermissionResponse(community.IDString(), chatId, channelPermissionsResponse)
  3469  		if err != nil {
  3470  			return nil, err
  3471  		}
  3472  		response.Channels[chatId] = channelPermissionsResponse
  3473  	}
  3474  	return response, nil
  3475  }
  3476  
  3477  func (m *Manager) GetCheckChannelPermissionResponses(communityID types.HexBytes) (*CheckAllChannelsPermissionsResponse, error) {
  3478  
  3479  	response, err := m.persistence.GetCheckChannelPermissionResponses(communityID.String())
  3480  	if err != nil {
  3481  		return nil, err
  3482  	}
  3483  	return &CheckAllChannelsPermissionsResponse{Channels: response}, nil
  3484  }
  3485  
  3486  type CheckAllChannelsPermissionsResponse struct {
  3487  	Channels map[string]*CheckChannelPermissionsResponse `json:"channels"`
  3488  }
  3489  
  3490  func (m *Manager) HandleCommunityRequestToJoinResponse(signer *ecdsa.PublicKey, request *protobuf.CommunityRequestToJoinResponse) (*RequestToJoin, error) {
  3491  	m.communityLock.Lock(request.CommunityId)
  3492  	defer m.communityLock.Unlock(request.CommunityId)
  3493  
  3494  	pkString := common.PubkeyToHex(&m.identity.PublicKey)
  3495  
  3496  	community, err := m.GetByID(request.CommunityId)
  3497  	if err != nil {
  3498  		return nil, err
  3499  	}
  3500  
  3501  	communityDescriptionBytes, err := proto.Marshal(request.Community)
  3502  	if err != nil {
  3503  		return nil, err
  3504  	}
  3505  
  3506  	// We need to wrap `request.Community` in an `ApplicationMetadataMessage`
  3507  	// of type `CommunityDescription` because `UpdateCommunityDescription` expects this.
  3508  	//
  3509  	// This is merely for marsheling/unmarsheling, hence we attaching a `Signature`
  3510  	// is not needed.
  3511  	metadataMessage := &protobuf.ApplicationMetadataMessage{
  3512  		Payload: communityDescriptionBytes,
  3513  		Type:    protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION,
  3514  	}
  3515  
  3516  	appMetadataMsg, err := proto.Marshal(metadataMessage)
  3517  	if err != nil {
  3518  		return nil, err
  3519  	}
  3520  
  3521  	isControlNodeSigner := common.IsPubKeyEqual(community.ControlNode(), signer)
  3522  	if !isControlNodeSigner {
  3523  		m.logger.Debug("signer is not control node", zap.String("signer", common.PubkeyToHex(signer)), zap.String("controlNode", common.PubkeyToHex(community.ControlNode())))
  3524  		return nil, ErrNotAuthorized
  3525  	}
  3526  
  3527  	_, processedDescription, err := m.preprocessDescription(community.ID(), request.Community)
  3528  	if err != nil {
  3529  		return nil, err
  3530  	}
  3531  
  3532  	_, err = community.UpdateCommunityDescription(processedDescription, appMetadataMsg, nil)
  3533  	if err != nil {
  3534  		return nil, err
  3535  	}
  3536  
  3537  	if err = m.handleCommunityTokensMetadata(community); err != nil {
  3538  		return nil, err
  3539  	}
  3540  
  3541  	if community.Encrypted() && len(request.Grant) > 0 {
  3542  		_, err = m.HandleCommunityGrant(community, request.Grant, request.Clock)
  3543  		if err != nil && err != ErrGrantOlder && err != ErrGrantExpired {
  3544  			m.logger.Error("Error handling a community grant", zap.Error(err))
  3545  		}
  3546  	}
  3547  
  3548  	err = m.persistence.SaveCommunity(community)
  3549  
  3550  	if err != nil {
  3551  		return nil, err
  3552  	}
  3553  
  3554  	if request.Accepted {
  3555  		err = m.markRequestToJoinAsAccepted(&m.identity.PublicKey, community)
  3556  		if err != nil {
  3557  			return nil, err
  3558  		}
  3559  	} else {
  3560  
  3561  		err = m.persistence.SetRequestToJoinState(pkString, community.ID(), RequestToJoinStateDeclined)
  3562  		if err != nil {
  3563  			return nil, err
  3564  		}
  3565  	}
  3566  
  3567  	return m.persistence.GetRequestToJoinByPkAndCommunityID(pkString, community.ID())
  3568  }
  3569  
  3570  func (m *Manager) HandleCommunityRequestToLeave(signer *ecdsa.PublicKey, proto *protobuf.CommunityRequestToLeave) error {
  3571  	requestToLeave := NewRequestToLeave(common.PubkeyToHex(signer), proto)
  3572  	if err := m.persistence.SaveRequestToLeave(requestToLeave); err != nil {
  3573  		return err
  3574  	}
  3575  
  3576  	// Ensure corresponding requestToJoin clock is older than requestToLeave
  3577  	requestToJoin, err := m.persistence.GetRequestToJoin(requestToLeave.ID)
  3578  	if err != nil {
  3579  		return err
  3580  	}
  3581  	if requestToJoin.Clock > requestToLeave.Clock {
  3582  		return ErrOldRequestToLeave
  3583  	}
  3584  
  3585  	return nil
  3586  }
  3587  
  3588  func UnwrapCommunityDescriptionMessage(payload []byte) (*ecdsa.PublicKey, *protobuf.CommunityDescription, error) {
  3589  
  3590  	applicationMetadataMessage := &protobuf.ApplicationMetadataMessage{}
  3591  	err := proto.Unmarshal(payload, applicationMetadataMessage)
  3592  	if err != nil {
  3593  		return nil, nil, err
  3594  	}
  3595  	if applicationMetadataMessage.Type != protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION {
  3596  		return nil, nil, ErrInvalidMessage
  3597  	}
  3598  	signer, err := utils.RecoverKey(applicationMetadataMessage)
  3599  	if err != nil {
  3600  		return nil, nil, err
  3601  	}
  3602  
  3603  	description := &protobuf.CommunityDescription{}
  3604  
  3605  	err = proto.Unmarshal(applicationMetadataMessage.Payload, description)
  3606  	if err != nil {
  3607  		return nil, nil, err
  3608  	}
  3609  
  3610  	return signer, description, nil
  3611  }
  3612  
  3613  func (m *Manager) JoinCommunity(id types.HexBytes, forceJoin bool) (*Community, error) {
  3614  	m.communityLock.Lock(id)
  3615  	defer m.communityLock.Unlock(id)
  3616  
  3617  	community, err := m.GetByID(id)
  3618  	if err != nil {
  3619  		return nil, err
  3620  	}
  3621  	if !forceJoin && community.Joined() {
  3622  		// Nothing to do, we are already joined
  3623  		return community, ErrOrgAlreadyJoined
  3624  	}
  3625  	community.Join()
  3626  	err = m.persistence.SaveCommunity(community)
  3627  	if err != nil {
  3628  		return nil, err
  3629  	}
  3630  	return community, nil
  3631  }
  3632  
  3633  func (m *Manager) SpectateCommunity(id types.HexBytes) (*Community, error) {
  3634  	m.communityLock.Lock(id)
  3635  	defer m.communityLock.Unlock(id)
  3636  
  3637  	community, err := m.GetByID(id)
  3638  	if err != nil {
  3639  		return nil, err
  3640  	}
  3641  	community.Spectate()
  3642  	if err = m.persistence.SaveCommunity(community); err != nil {
  3643  		return nil, err
  3644  	}
  3645  	return community, nil
  3646  }
  3647  
  3648  func (m *Manager) GetMagnetlinkMessageClock(communityID types.HexBytes) (uint64, error) {
  3649  	return m.persistence.GetMagnetlinkMessageClock(communityID)
  3650  }
  3651  
  3652  func (m *Manager) GetCommunityRequestToJoinClock(pk *ecdsa.PublicKey, communityID string) (uint64, error) {
  3653  	communityIDBytes, err := types.DecodeHex(communityID)
  3654  	if err != nil {
  3655  		return 0, err
  3656  	}
  3657  
  3658  	joinClock, err := m.persistence.GetRequestToJoinClockByPkAndCommunityID(common.PubkeyToHex(pk), communityIDBytes)
  3659  
  3660  	if errors.Is(err, sql.ErrNoRows) {
  3661  		return 0, nil
  3662  	} else if err != nil {
  3663  		return 0, err
  3664  	}
  3665  
  3666  	return joinClock, nil
  3667  }
  3668  
  3669  func (m *Manager) GetRequestToJoinByPkAndCommunityID(pk *ecdsa.PublicKey, communityID []byte) (*RequestToJoin, error) {
  3670  	return m.persistence.GetRequestToJoinByPkAndCommunityID(common.PubkeyToHex(pk), communityID)
  3671  }
  3672  
  3673  func (m *Manager) UpdateCommunityDescriptionMagnetlinkMessageClock(communityID types.HexBytes, clock uint64) error {
  3674  	m.communityLock.Lock(communityID)
  3675  	defer m.communityLock.Unlock(communityID)
  3676  
  3677  	community, err := m.GetByIDString(communityID.String())
  3678  	if err != nil {
  3679  		return err
  3680  	}
  3681  	community.config.CommunityDescription.ArchiveMagnetlinkClock = clock
  3682  	return m.persistence.SaveCommunity(community)
  3683  }
  3684  
  3685  func (m *Manager) UpdateMagnetlinkMessageClock(communityID types.HexBytes, clock uint64) error {
  3686  	return m.persistence.UpdateMagnetlinkMessageClock(communityID, clock)
  3687  }
  3688  
  3689  func (m *Manager) UpdateLastSeenMagnetlink(communityID types.HexBytes, magnetlinkURI string) error {
  3690  	return m.persistence.UpdateLastSeenMagnetlink(communityID, magnetlinkURI)
  3691  }
  3692  
  3693  func (m *Manager) GetLastSeenMagnetlink(communityID types.HexBytes) (string, error) {
  3694  	return m.persistence.GetLastSeenMagnetlink(communityID)
  3695  }
  3696  
  3697  func (m *Manager) LeaveCommunity(id types.HexBytes) (*Community, error) {
  3698  	m.communityLock.Lock(id)
  3699  	defer m.communityLock.Unlock(id)
  3700  
  3701  	community, err := m.GetByID(id)
  3702  	if err != nil {
  3703  		return nil, err
  3704  	}
  3705  
  3706  	community.RemoveOurselvesFromOrg(&m.identity.PublicKey)
  3707  	community.Leave()
  3708  
  3709  	if err = m.persistence.SaveCommunity(community); err != nil {
  3710  		return nil, err
  3711  	}
  3712  
  3713  	return community, nil
  3714  }
  3715  
  3716  // Same as LeaveCommunity, but we have an option to stay spectating
  3717  func (m *Manager) KickedOutOfCommunity(id types.HexBytes, spectateMode bool) (*Community, error) {
  3718  	m.communityLock.Lock(id)
  3719  	defer m.communityLock.Unlock(id)
  3720  
  3721  	community, err := m.GetByID(id)
  3722  	if err != nil {
  3723  		return nil, err
  3724  	}
  3725  
  3726  	community.RemoveOurselvesFromOrg(&m.identity.PublicKey)
  3727  	community.Leave()
  3728  	if spectateMode {
  3729  		community.Spectate()
  3730  	}
  3731  
  3732  	if err = m.persistence.SaveCommunity(community); err != nil {
  3733  		return nil, err
  3734  	}
  3735  
  3736  	return community, nil
  3737  }
  3738  
  3739  func (m *Manager) AddMemberOwnerToCommunity(communityID types.HexBytes, pk *ecdsa.PublicKey) (*Community, error) {
  3740  	m.communityLock.Lock(communityID)
  3741  	defer m.communityLock.Unlock(communityID)
  3742  
  3743  	community, err := m.GetByID(communityID)
  3744  	if err != nil {
  3745  		return nil, err
  3746  	}
  3747  
  3748  	_, err = community.AddMember(pk, []protobuf.CommunityMember_Roles{protobuf.CommunityMember_ROLE_OWNER}, community.Clock())
  3749  	if err != nil {
  3750  		return nil, err
  3751  	}
  3752  
  3753  	err = m.persistence.SaveCommunity(community)
  3754  	if err != nil {
  3755  		return nil, err
  3756  	}
  3757  
  3758  	m.publish(&Subscription{Community: community})
  3759  	return community, nil
  3760  }
  3761  
  3762  func (m *Manager) RemoveUserFromCommunity(id types.HexBytes, pk *ecdsa.PublicKey) (*Community, error) {
  3763  	m.communityLock.Lock(id)
  3764  	defer m.communityLock.Unlock(id)
  3765  
  3766  	community, err := m.GetByID(id)
  3767  	if err != nil {
  3768  		return nil, err
  3769  	}
  3770  
  3771  	_, err = community.RemoveUserFromOrg(pk)
  3772  	if err != nil {
  3773  		return nil, err
  3774  	}
  3775  
  3776  	err = m.saveAndPublish(community)
  3777  	if err != nil {
  3778  		return nil, err
  3779  	}
  3780  
  3781  	return community, nil
  3782  }
  3783  
  3784  func (m *Manager) UnbanUserFromCommunity(request *requests.UnbanUserFromCommunity) (*Community, error) {
  3785  	m.communityLock.Lock(request.CommunityID)
  3786  	defer m.communityLock.Unlock(request.CommunityID)
  3787  
  3788  	id := request.CommunityID
  3789  	publicKey, err := common.HexToPubkey(request.User.String())
  3790  	if err != nil {
  3791  		return nil, err
  3792  	}
  3793  
  3794  	community, err := m.GetByID(id)
  3795  	if err != nil {
  3796  		return nil, err
  3797  	}
  3798  
  3799  	_, err = community.UnbanUserFromCommunity(publicKey)
  3800  	if err != nil {
  3801  		return nil, err
  3802  	}
  3803  
  3804  	err = m.saveAndPublish(community)
  3805  	if err != nil {
  3806  		return nil, err
  3807  	}
  3808  
  3809  	return community, nil
  3810  }
  3811  
  3812  func (m *Manager) AddRoleToMember(request *requests.AddRoleToMember) (*Community, error) {
  3813  	m.communityLock.Lock(request.CommunityID)
  3814  	defer m.communityLock.Unlock(request.CommunityID)
  3815  
  3816  	id := request.CommunityID
  3817  	publicKey, err := common.HexToPubkey(request.User.String())
  3818  	if err != nil {
  3819  		return nil, err
  3820  	}
  3821  
  3822  	community, err := m.GetByID(id)
  3823  	if err != nil {
  3824  		return nil, err
  3825  	}
  3826  
  3827  	if !community.hasMember(publicKey) {
  3828  		return nil, ErrMemberNotFound
  3829  	}
  3830  
  3831  	_, err = community.AddRoleToMember(publicKey, request.Role)
  3832  	if err != nil {
  3833  		return nil, err
  3834  	}
  3835  
  3836  	err = m.persistence.SaveCommunity(community)
  3837  	if err != nil {
  3838  		return nil, err
  3839  	}
  3840  
  3841  	m.publish(&Subscription{Community: community})
  3842  
  3843  	return community, nil
  3844  }
  3845  
  3846  func (m *Manager) RemoveRoleFromMember(request *requests.RemoveRoleFromMember) (*Community, error) {
  3847  	m.communityLock.Lock(request.CommunityID)
  3848  	defer m.communityLock.Unlock(request.CommunityID)
  3849  
  3850  	id := request.CommunityID
  3851  	publicKey, err := common.HexToPubkey(request.User.String())
  3852  	if err != nil {
  3853  		return nil, err
  3854  	}
  3855  
  3856  	community, err := m.GetByID(id)
  3857  	if err != nil {
  3858  		return nil, err
  3859  	}
  3860  
  3861  	if !community.hasMember(publicKey) {
  3862  		return nil, ErrMemberNotFound
  3863  	}
  3864  
  3865  	_, err = community.RemoveRoleFromMember(publicKey, request.Role)
  3866  	if err != nil {
  3867  		return nil, err
  3868  	}
  3869  
  3870  	err = m.persistence.SaveCommunity(community)
  3871  	if err != nil {
  3872  		return nil, err
  3873  	}
  3874  
  3875  	m.publish(&Subscription{Community: community})
  3876  
  3877  	return community, nil
  3878  }
  3879  
  3880  func (m *Manager) BanUserFromCommunity(request *requests.BanUserFromCommunity) (*Community, error) {
  3881  	m.communityLock.Lock(request.CommunityID)
  3882  	defer m.communityLock.Unlock(request.CommunityID)
  3883  
  3884  	id := request.CommunityID
  3885  
  3886  	publicKey, err := common.HexToPubkey(request.User.String())
  3887  	if err != nil {
  3888  		return nil, err
  3889  	}
  3890  
  3891  	community, err := m.GetByID(id)
  3892  	if err != nil {
  3893  		return nil, err
  3894  	}
  3895  
  3896  	_, err = community.BanUserFromCommunity(publicKey, &protobuf.CommunityBanInfo{DeleteAllMessages: request.DeleteAllMessages})
  3897  	if err != nil {
  3898  		return nil, err
  3899  	}
  3900  
  3901  	err = m.saveAndPublish(community)
  3902  	if err != nil {
  3903  		return nil, err
  3904  	}
  3905  
  3906  	return community, nil
  3907  }
  3908  
  3909  func (m *Manager) dbRecordBundleToCommunity(r *CommunityRecordBundle) (*Community, error) {
  3910  	var descriptionEncryptor DescriptionEncryptor
  3911  	if m.encryptor != nil {
  3912  		descriptionEncryptor = m
  3913  	}
  3914  
  3915  	initializer := func(community *Community) error {
  3916  		_, description, err := m.preprocessDescription(community.ID(), community.config.CommunityDescription)
  3917  		if err != nil {
  3918  			return err
  3919  		}
  3920  
  3921  		community.config.CommunityDescription = description
  3922  
  3923  		if community.config.EventsData != nil {
  3924  			eventsDescription, err := validateAndGetEventsMessageCommunityDescription(community.config.EventsData.EventsBaseCommunityDescription, community.ControlNode())
  3925  			if err != nil {
  3926  				m.logger.Error("invalid EventsBaseCommunityDescription", zap.Error(err))
  3927  			}
  3928  			if eventsDescription != nil && eventsDescription.Clock == community.Clock() {
  3929  				community.applyEvents()
  3930  			}
  3931  		}
  3932  
  3933  		if m.transport != nil && m.transport.WakuVersion() == 2 {
  3934  			topic := community.PubsubTopic()
  3935  			privKey, err := m.transport.RetrievePubsubTopicKey(topic)
  3936  			if err != nil {
  3937  				return err
  3938  			}
  3939  			community.config.PubsubTopicPrivateKey = privKey
  3940  		}
  3941  
  3942  		return nil
  3943  	}
  3944  
  3945  	return recordBundleToCommunity(
  3946  		r,
  3947  		m.identity,
  3948  		m.installationID,
  3949  		m.logger,
  3950  		m.timesource,
  3951  		descriptionEncryptor,
  3952  		m.mediaServer,
  3953  		initializer,
  3954  	)
  3955  }
  3956  
  3957  func (m *Manager) GetByID(id []byte) (*Community, error) {
  3958  	community, err := m.persistence.GetByID(&m.identity.PublicKey, id)
  3959  	if err != nil {
  3960  		return nil, err
  3961  	}
  3962  	if community == nil {
  3963  		return nil, ErrOrgNotFound
  3964  	}
  3965  	return community, nil
  3966  }
  3967  
  3968  func (m *Manager) GetByIDString(idString string) (*Community, error) {
  3969  	id, err := types.DecodeHex(idString)
  3970  	if err != nil {
  3971  		return nil, err
  3972  	}
  3973  	return m.GetByID(id)
  3974  }
  3975  
  3976  func (m *Manager) GetCommunityShard(communityID types.HexBytes) (*shard.Shard, error) {
  3977  	return m.persistence.GetCommunityShard(communityID)
  3978  }
  3979  
  3980  func (m *Manager) SaveCommunityShard(communityID types.HexBytes, shard *shard.Shard, clock uint64) error {
  3981  	m.communityLock.Lock(communityID)
  3982  	defer m.communityLock.Unlock(communityID)
  3983  
  3984  	return m.persistence.SaveCommunityShard(communityID, shard, clock)
  3985  }
  3986  
  3987  func (m *Manager) DeleteCommunityShard(communityID types.HexBytes) error {
  3988  	m.communityLock.Lock(communityID)
  3989  	defer m.communityLock.Unlock(communityID)
  3990  
  3991  	return m.persistence.DeleteCommunityShard(communityID)
  3992  }
  3993  
  3994  func (m *Manager) SaveRequestToJoinRevealedAddresses(requestID types.HexBytes, revealedAccounts []*protobuf.RevealedAccount) error {
  3995  	return m.persistence.SaveRequestToJoinRevealedAddresses(requestID, revealedAccounts)
  3996  }
  3997  
  3998  func (m *Manager) RemoveRequestToJoinRevealedAddresses(requestID types.HexBytes) error {
  3999  	return m.persistence.RemoveRequestToJoinRevealedAddresses(requestID)
  4000  }
  4001  
  4002  func (m *Manager) SaveRequestToJoinAndCommunity(requestToJoin *RequestToJoin, community *Community) (*Community, *RequestToJoin, error) {
  4003  	if err := m.persistence.SaveRequestToJoin(requestToJoin); err != nil {
  4004  		return nil, nil, err
  4005  	}
  4006  	community.config.RequestedToJoinAt = uint64(time.Now().Unix())
  4007  	community.AddRequestToJoin(requestToJoin)
  4008  
  4009  	// Save revealed addresses to our own table so that we can retrieve them later when editing
  4010  	if err := m.SaveRequestToJoinRevealedAddresses(requestToJoin.ID, requestToJoin.RevealedAccounts); err != nil {
  4011  		return nil, nil, err
  4012  	}
  4013  
  4014  	return community, requestToJoin, nil
  4015  }
  4016  
  4017  func (m *Manager) CreateRequestToJoin(request *requests.RequestToJoinCommunity, customizationColor multiaccountscommon.CustomizationColor) *RequestToJoin {
  4018  	clock := uint64(time.Now().Unix())
  4019  	requestToJoin := &RequestToJoin{
  4020  		PublicKey:            common.PubkeyToHex(&m.identity.PublicKey),
  4021  		Clock:                clock,
  4022  		ENSName:              request.ENSName,
  4023  		CommunityID:          request.CommunityID,
  4024  		State:                RequestToJoinStatePending,
  4025  		Our:                  true,
  4026  		RevealedAccounts:     make([]*protobuf.RevealedAccount, 0),
  4027  		CustomizationColor:   customizationColor,
  4028  		ShareFutureAddresses: request.ShareFutureAddresses,
  4029  	}
  4030  
  4031  	requestToJoin.CalculateID()
  4032  
  4033  	addSignature := len(request.Signatures) == len(request.AddressesToReveal)
  4034  	for i := range request.AddressesToReveal {
  4035  		revealedAcc := &protobuf.RevealedAccount{
  4036  			Address:          request.AddressesToReveal[i],
  4037  			IsAirdropAddress: types.HexToAddress(request.AddressesToReveal[i]) == types.HexToAddress(request.AirdropAddress),
  4038  		}
  4039  
  4040  		if addSignature {
  4041  			revealedAcc.Signature = request.Signatures[i]
  4042  		}
  4043  
  4044  		requestToJoin.RevealedAccounts = append(requestToJoin.RevealedAccounts, revealedAcc)
  4045  	}
  4046  
  4047  	return requestToJoin
  4048  }
  4049  
  4050  func (m *Manager) SaveRequestToJoin(request *RequestToJoin) error {
  4051  	return m.persistence.SaveRequestToJoin(request)
  4052  }
  4053  
  4054  func (m *Manager) CanceledRequestsToJoinForUser(pk *ecdsa.PublicKey) ([]*RequestToJoin, error) {
  4055  	return m.persistence.CanceledRequestsToJoinForUser(common.PubkeyToHex(pk))
  4056  }
  4057  
  4058  func (m *Manager) PendingRequestsToJoin() ([]*RequestToJoin, error) {
  4059  	return m.persistence.PendingRequestsToJoin()
  4060  }
  4061  
  4062  func (m *Manager) PendingRequestsToJoinForUser(pk *ecdsa.PublicKey) ([]*RequestToJoin, error) {
  4063  	return m.persistence.RequestsToJoinForUserByState(common.PubkeyToHex(pk), RequestToJoinStatePending)
  4064  }
  4065  
  4066  func (m *Manager) PendingRequestsToJoinForCommunity(id types.HexBytes) ([]*RequestToJoin, error) {
  4067  	m.logger.Info("fetching pending invitations", zap.String("community-id", id.String()))
  4068  	return m.persistence.PendingRequestsToJoinForCommunity(id)
  4069  }
  4070  
  4071  func (m *Manager) DeclinedRequestsToJoinForCommunity(id types.HexBytes) ([]*RequestToJoin, error) {
  4072  	m.logger.Info("fetching declined invitations", zap.String("community-id", id.String()))
  4073  	return m.persistence.DeclinedRequestsToJoinForCommunity(id)
  4074  }
  4075  
  4076  func (m *Manager) CanceledRequestsToJoinForCommunity(id types.HexBytes) ([]*RequestToJoin, error) {
  4077  	m.logger.Info("fetching canceled invitations", zap.String("community-id", id.String()))
  4078  	return m.persistence.CanceledRequestsToJoinForCommunity(id)
  4079  }
  4080  
  4081  func (m *Manager) AcceptedRequestsToJoinForCommunity(id types.HexBytes) ([]*RequestToJoin, error) {
  4082  	m.logger.Info("fetching canceled invitations", zap.String("community-id", id.String()))
  4083  	return m.persistence.AcceptedRequestsToJoinForCommunity(id)
  4084  }
  4085  
  4086  func (m *Manager) AcceptedPendingRequestsToJoinForCommunity(id types.HexBytes) ([]*RequestToJoin, error) {
  4087  	return m.persistence.AcceptedPendingRequestsToJoinForCommunity(id)
  4088  }
  4089  
  4090  func (m *Manager) DeclinedPendingRequestsToJoinForCommunity(id types.HexBytes) ([]*RequestToJoin, error) {
  4091  	return m.persistence.DeclinedPendingRequestsToJoinForCommunity(id)
  4092  }
  4093  
  4094  func (m *Manager) AllNonApprovedCommunitiesRequestsToJoin() ([]*RequestToJoin, error) {
  4095  	m.logger.Info("fetching all non-approved invitations for all communities")
  4096  	return m.persistence.AllNonApprovedCommunitiesRequestsToJoin()
  4097  }
  4098  
  4099  func (m *Manager) RequestsToJoinForCommunityAwaitingAddresses(id types.HexBytes) ([]*RequestToJoin, error) {
  4100  	m.logger.Info("fetching ownership changed invitations", zap.String("community-id", id.String()))
  4101  	return m.persistence.RequestsToJoinForCommunityAwaitingAddresses(id)
  4102  }
  4103  
  4104  func (m *Manager) CanPost(pk *ecdsa.PublicKey, communityID string, chatID string, messageType protobuf.ApplicationMetadataMessage_Type) (bool, error) {
  4105  	community, err := m.GetByIDString(communityID)
  4106  	if err != nil {
  4107  		return false, err
  4108  	}
  4109  	return community.CanPost(pk, chatID, messageType)
  4110  }
  4111  
  4112  func (m *Manager) IsEncrypted(communityID string) (bool, error) {
  4113  	community, err := m.GetByIDString(communityID)
  4114  	if err != nil {
  4115  		return false, err
  4116  	}
  4117  
  4118  	return community.Encrypted(), nil
  4119  }
  4120  
  4121  func (m *Manager) IsChannelEncrypted(communityID string, chatID string) (bool, error) {
  4122  	community, err := m.GetByIDString(communityID)
  4123  	if err != nil {
  4124  		return false, err
  4125  	}
  4126  
  4127  	channelID := strings.TrimPrefix(chatID, communityID)
  4128  	return community.ChannelEncrypted(channelID), nil
  4129  }
  4130  
  4131  func (m *Manager) ShouldHandleSyncCommunity(community *protobuf.SyncInstallationCommunity) (bool, error) {
  4132  	return m.persistence.ShouldHandleSyncCommunity(community)
  4133  }
  4134  
  4135  func (m *Manager) ShouldHandleSyncCommunitySettings(communitySettings *protobuf.SyncCommunitySettings) (bool, error) {
  4136  	return m.persistence.ShouldHandleSyncCommunitySettings(communitySettings)
  4137  }
  4138  
  4139  func (m *Manager) HandleSyncCommunitySettings(syncCommunitySettings *protobuf.SyncCommunitySettings) (*CommunitySettings, error) {
  4140  	id, err := types.DecodeHex(syncCommunitySettings.CommunityId)
  4141  	if err != nil {
  4142  		return nil, err
  4143  	}
  4144  
  4145  	settings, err := m.persistence.GetCommunitySettingsByID(id)
  4146  	if err != nil {
  4147  		return nil, err
  4148  	}
  4149  
  4150  	if settings == nil {
  4151  		settings = &CommunitySettings{
  4152  			CommunityID:                  syncCommunitySettings.CommunityId,
  4153  			HistoryArchiveSupportEnabled: syncCommunitySettings.HistoryArchiveSupportEnabled,
  4154  			Clock:                        syncCommunitySettings.Clock,
  4155  		}
  4156  	}
  4157  
  4158  	if syncCommunitySettings.Clock > settings.Clock {
  4159  		settings.CommunityID = syncCommunitySettings.CommunityId
  4160  		settings.HistoryArchiveSupportEnabled = syncCommunitySettings.HistoryArchiveSupportEnabled
  4161  		settings.Clock = syncCommunitySettings.Clock
  4162  	}
  4163  
  4164  	err = m.persistence.SaveCommunitySettings(*settings)
  4165  	if err != nil {
  4166  		return nil, err
  4167  	}
  4168  	return settings, nil
  4169  }
  4170  
  4171  func (m *Manager) SetSyncClock(id []byte, clock uint64) error {
  4172  	return m.persistence.SetSyncClock(id, clock)
  4173  }
  4174  
  4175  func (m *Manager) SetPrivateKey(id []byte, privKey *ecdsa.PrivateKey) error {
  4176  	return m.persistence.SetPrivateKey(id, privKey)
  4177  }
  4178  
  4179  func (m *Manager) GetSyncedRawCommunity(id []byte) (*RawCommunityRow, error) {
  4180  	return m.persistence.getSyncedRawCommunity(id)
  4181  }
  4182  
  4183  func (m *Manager) GetCommunitySettingsByID(id types.HexBytes) (*CommunitySettings, error) {
  4184  	return m.persistence.GetCommunitySettingsByID(id)
  4185  }
  4186  
  4187  func (m *Manager) GetCommunitiesSettings() ([]CommunitySettings, error) {
  4188  	return m.persistence.GetCommunitiesSettings()
  4189  }
  4190  
  4191  func (m *Manager) SaveCommunitySettings(settings CommunitySettings) error {
  4192  	return m.persistence.SaveCommunitySettings(settings)
  4193  }
  4194  
  4195  func (m *Manager) CommunitySettingsExist(id types.HexBytes) (bool, error) {
  4196  	return m.persistence.CommunitySettingsExist(id)
  4197  }
  4198  
  4199  func (m *Manager) DeleteCommunitySettings(id types.HexBytes) error {
  4200  	return m.persistence.DeleteCommunitySettings(id)
  4201  }
  4202  
  4203  func (m *Manager) UpdateCommunitySettings(settings CommunitySettings) error {
  4204  	return m.persistence.UpdateCommunitySettings(settings)
  4205  }
  4206  
  4207  func (m *Manager) GetOwnedCommunitiesChatIDs() (map[string]bool, error) {
  4208  	ownedCommunities, err := m.Controlled()
  4209  	if err != nil {
  4210  		return nil, err
  4211  	}
  4212  
  4213  	chatIDs := make(map[string]bool)
  4214  	for _, c := range ownedCommunities {
  4215  		if c.Joined() {
  4216  			for _, id := range c.ChatIDs() {
  4217  				chatIDs[id] = true
  4218  			}
  4219  		}
  4220  	}
  4221  	return chatIDs, nil
  4222  }
  4223  
  4224  func (m *Manager) StoreWakuMessage(message *types.Message) error {
  4225  	return m.persistence.SaveWakuMessage(message)
  4226  }
  4227  
  4228  func (m *Manager) StoreWakuMessages(messages []*types.Message) error {
  4229  	return m.persistence.SaveWakuMessages(messages)
  4230  }
  4231  
  4232  func (m *Manager) GetLatestWakuMessageTimestamp(topics []types.TopicType) (uint64, error) {
  4233  	return m.persistence.GetLatestWakuMessageTimestamp(topics)
  4234  }
  4235  
  4236  func (m *Manager) GetCommunityToken(communityID string, chainID int, address string) (*community_token.CommunityToken, error) {
  4237  	return m.persistence.GetCommunityToken(communityID, chainID, address)
  4238  }
  4239  
  4240  func (m *Manager) GetCommunityTokenByChainAndAddress(chainID int, address string) (*community_token.CommunityToken, error) {
  4241  	return m.persistence.GetCommunityTokenByChainAndAddress(chainID, address)
  4242  }
  4243  
  4244  func (m *Manager) GetCommunityTokens(communityID string) ([]*community_token.CommunityToken, error) {
  4245  	return m.persistence.GetCommunityTokens(communityID)
  4246  }
  4247  
  4248  func (m *Manager) GetAllCommunityTokens() ([]*community_token.CommunityToken, error) {
  4249  	return m.persistence.GetAllCommunityTokens()
  4250  }
  4251  
  4252  func (m *Manager) GetCommunityGrant(communityID string) ([]byte, uint64, error) {
  4253  	return m.persistence.GetCommunityGrant(communityID)
  4254  }
  4255  
  4256  func (m *Manager) ImageToBase64(uri string) string {
  4257  	if uri == "" {
  4258  		return ""
  4259  	}
  4260  	file, err := os.Open(uri)
  4261  	if err != nil {
  4262  		m.logger.Error(err.Error())
  4263  		return ""
  4264  	}
  4265  	defer file.Close()
  4266  
  4267  	payload, err := ioutil.ReadAll(file)
  4268  	if err != nil {
  4269  		m.logger.Error(err.Error())
  4270  		return ""
  4271  	}
  4272  	base64img, err := images.GetPayloadDataURI(payload)
  4273  	if err != nil {
  4274  		m.logger.Error(err.Error())
  4275  		return ""
  4276  	}
  4277  	return base64img
  4278  }
  4279  
  4280  func (m *Manager) SaveCommunityToken(token *community_token.CommunityToken, croppedImage *images.CroppedImage) (*community_token.CommunityToken, error) {
  4281  
  4282  	_, err := m.GetByIDString(token.CommunityID)
  4283  	if err != nil {
  4284  		return nil, err
  4285  	}
  4286  
  4287  	if croppedImage != nil && croppedImage.ImagePath != "" {
  4288  		bytes, err := images.OpenAndAdjustImage(*croppedImage, true)
  4289  		if err != nil {
  4290  			return nil, err
  4291  		}
  4292  
  4293  		base64img, err := images.GetPayloadDataURI(bytes)
  4294  		if err != nil {
  4295  			return nil, err
  4296  		}
  4297  		token.Base64Image = base64img
  4298  	} else if !images.IsPayloadDataURI(token.Base64Image) {
  4299  		// if image is already base64 do not convert (owner and master tokens have already base64 image)
  4300  		token.Base64Image = m.ImageToBase64(token.Base64Image)
  4301  	}
  4302  
  4303  	return token, m.persistence.AddCommunityToken(token)
  4304  }
  4305  
  4306  func (m *Manager) AddCommunityToken(token *community_token.CommunityToken, clock uint64) (*Community, error) {
  4307  	if token == nil {
  4308  		return nil, errors.New("Token is absent in database")
  4309  	}
  4310  
  4311  	communityID, err := types.DecodeHex(token.CommunityID)
  4312  	if err != nil {
  4313  		return nil, err
  4314  	}
  4315  
  4316  	m.communityLock.Lock(communityID)
  4317  	defer m.communityLock.Unlock(communityID)
  4318  
  4319  	community, err := m.GetByID(communityID)
  4320  	if err != nil {
  4321  		return nil, err
  4322  	}
  4323  
  4324  	if !community.MemberCanManageToken(&m.identity.PublicKey, token) {
  4325  		return nil, ErrInvalidManageTokensPermission
  4326  	}
  4327  
  4328  	tokenMetadata := &protobuf.CommunityTokenMetadata{
  4329  		ContractAddresses: map[uint64]string{uint64(token.ChainID): token.Address},
  4330  		Description:       token.Description,
  4331  		Image:             token.Base64Image,
  4332  		Symbol:            token.Symbol,
  4333  		TokenType:         token.TokenType,
  4334  		Name:              token.Name,
  4335  		Decimals:          uint32(token.Decimals),
  4336  		Version:           token.Version,
  4337  	}
  4338  	_, err = community.AddCommunityTokensMetadata(tokenMetadata)
  4339  	if err != nil {
  4340  		return nil, err
  4341  	}
  4342  
  4343  	if community.IsControlNode() && (token.PrivilegesLevel == community_token.MasterLevel || token.PrivilegesLevel == community_token.OwnerLevel) {
  4344  		permissionType := protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER
  4345  		if token.PrivilegesLevel == community_token.MasterLevel {
  4346  			permissionType = protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER
  4347  		}
  4348  
  4349  		contractAddresses := make(map[uint64]string)
  4350  		contractAddresses[uint64(token.ChainID)] = token.Address
  4351  
  4352  		tokenCriteria := &protobuf.TokenCriteria{
  4353  			ContractAddresses: contractAddresses,
  4354  			Type:              protobuf.CommunityTokenType_ERC721,
  4355  			Symbol:            token.Symbol,
  4356  			Name:              token.Name,
  4357  			Amount:            "1",
  4358  			AmountInWei:       "1",
  4359  			Decimals:          uint64(0),
  4360  		}
  4361  
  4362  		request := &requests.CreateCommunityTokenPermission{
  4363  			CommunityID:   community.ID(),
  4364  			Type:          permissionType,
  4365  			TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria},
  4366  			IsPrivate:     true,
  4367  			ChatIds:       []string{},
  4368  		}
  4369  
  4370  		community, _, err = m.createCommunityTokenPermission(request, community)
  4371  		if err != nil {
  4372  			return nil, err
  4373  		}
  4374  
  4375  		if token.PrivilegesLevel == community_token.OwnerLevel {
  4376  			_, err = m.promoteSelfToControlNode(community, clock)
  4377  			if err != nil {
  4378  				return nil, err
  4379  			}
  4380  		}
  4381  	}
  4382  
  4383  	return community, m.saveAndPublish(community)
  4384  }
  4385  
  4386  func (m *Manager) UpdateCommunityTokenState(chainID int, contractAddress string, deployState community_token.DeployState) error {
  4387  	return m.persistence.UpdateCommunityTokenState(chainID, contractAddress, deployState)
  4388  }
  4389  
  4390  func (m *Manager) UpdateCommunityTokenAddress(chainID int, oldContractAddress string, newContractAddress string) error {
  4391  	return m.persistence.UpdateCommunityTokenAddress(chainID, oldContractAddress, newContractAddress)
  4392  }
  4393  
  4394  func (m *Manager) UpdateCommunityTokenSupply(chainID int, contractAddress string, supply *bigint.BigInt) error {
  4395  	return m.persistence.UpdateCommunityTokenSupply(chainID, contractAddress, supply)
  4396  }
  4397  
  4398  func (m *Manager) RemoveCommunityToken(chainID int, contractAddress string) error {
  4399  	return m.persistence.RemoveCommunityToken(chainID, contractAddress)
  4400  }
  4401  
  4402  func (m *Manager) SetCommunityActiveMembersCount(communityID string, activeMembersCount uint64) error {
  4403  	id, err := types.DecodeHex(communityID)
  4404  	if err != nil {
  4405  		return err
  4406  	}
  4407  
  4408  	m.communityLock.Lock(id)
  4409  	defer m.communityLock.Unlock(id)
  4410  
  4411  	community, err := m.GetByID(id)
  4412  	if err != nil {
  4413  		return err
  4414  	}
  4415  
  4416  	updated, err := community.SetActiveMembersCount(activeMembersCount)
  4417  	if err != nil {
  4418  		return err
  4419  	}
  4420  
  4421  	if updated {
  4422  		if err = m.persistence.SaveCommunity(community); err != nil {
  4423  			return err
  4424  		}
  4425  
  4426  		m.publish(&Subscription{Community: community})
  4427  	}
  4428  
  4429  	return nil
  4430  }
  4431  
  4432  func combineAddressesAndChainIDs(addresses []gethcommon.Address, chainIDs []uint64) []*AccountChainIDsCombination {
  4433  	combinations := make([]*AccountChainIDsCombination, 0)
  4434  	for _, address := range addresses {
  4435  		combinations = append(combinations, &AccountChainIDsCombination{
  4436  			Address:  address,
  4437  			ChainIDs: chainIDs,
  4438  		})
  4439  	}
  4440  	return combinations
  4441  }
  4442  
  4443  func revealedAccountsToAccountsAndChainIDsCombination(revealedAccounts []*protobuf.RevealedAccount) []*AccountChainIDsCombination {
  4444  	accountsAndChainIDs := make([]*AccountChainIDsCombination, 0)
  4445  	for _, revealedAccount := range revealedAccounts {
  4446  		accountsAndChainIDs = append(accountsAndChainIDs, &AccountChainIDsCombination{
  4447  			Address:  gethcommon.HexToAddress(revealedAccount.Address),
  4448  			ChainIDs: revealedAccount.ChainIds,
  4449  		})
  4450  	}
  4451  	return accountsAndChainIDs
  4452  }
  4453  
  4454  func (m *Manager) accountsHasPrivilegedPermission(preParsedCommunityPermissionData *PreParsedCommunityPermissionsData, accounts []*AccountChainIDsCombination) bool {
  4455  	if preParsedCommunityPermissionData != nil {
  4456  		permissionResponse, err := m.PermissionChecker.CheckPermissions(preParsedCommunityPermissionData, accounts, true)
  4457  		if err != nil {
  4458  			m.logger.Warn("check privileged permission failed: %v", zap.Error(err))
  4459  			return false
  4460  		}
  4461  		return permissionResponse.Satisfied
  4462  	}
  4463  	return false
  4464  }
  4465  
  4466  func (m *Manager) saveAndPublish(community *Community) error {
  4467  	err := m.persistence.SaveCommunity(community)
  4468  	if err != nil {
  4469  		return err
  4470  	}
  4471  
  4472  	if community.IsControlNode() {
  4473  		m.publish(&Subscription{Community: community})
  4474  		return nil
  4475  	}
  4476  
  4477  	if community.HasPermissionToSendCommunityEvents() {
  4478  		err := m.signEvents(community)
  4479  		if err != nil {
  4480  			return err
  4481  		}
  4482  		err = m.persistence.SaveCommunityEvents(community)
  4483  		if err != nil {
  4484  			return err
  4485  		}
  4486  
  4487  		m.publish(&Subscription{CommunityEventsMessage: community.toCommunityEventsMessage()})
  4488  		return nil
  4489  	}
  4490  
  4491  	return nil
  4492  }
  4493  
  4494  func (m *Manager) GetRevealedAddresses(communityID types.HexBytes, memberPk string) ([]*protobuf.RevealedAccount, error) {
  4495  	logger := m.logger.Named("GetRevealedAddresses")
  4496  
  4497  	requestID := CalculateRequestID(memberPk, communityID)
  4498  	response, err := m.persistence.GetRequestToJoinRevealedAddresses(requestID)
  4499  
  4500  	revealedAddresses := make([]string, len(response))
  4501  	for i, acc := range response {
  4502  		revealedAddresses[i] = acc.Address
  4503  	}
  4504  	logger.Debug("Revealed addresses", zap.Any("Addresses:", revealedAddresses))
  4505  
  4506  	return response, err
  4507  }
  4508  
  4509  func (m *Manager) handleCommunityTokensMetadata(community *Community) error {
  4510  	communityID := community.IDString()
  4511  	communityTokens := community.CommunityTokensMetadata()
  4512  
  4513  	if len(communityTokens) == 0 {
  4514  		return nil
  4515  	}
  4516  	for _, tokenMetadata := range communityTokens {
  4517  		for chainID, address := range tokenMetadata.ContractAddresses {
  4518  			exists, err := m.persistence.HasCommunityToken(communityID, address, int(chainID))
  4519  			if err != nil {
  4520  				return err
  4521  			}
  4522  			if !exists {
  4523  				// Fetch community token to make sure it's stored in the DB, discard result
  4524  				communityToken, err := m.FetchCommunityToken(community, tokenMetadata, chainID, address)
  4525  				if err != nil {
  4526  					return err
  4527  				}
  4528  
  4529  				err = m.persistence.AddCommunityToken(communityToken)
  4530  				if err != nil {
  4531  					return err
  4532  				}
  4533  			}
  4534  		}
  4535  	}
  4536  	return nil
  4537  }
  4538  
  4539  func (m *Manager) HandleCommunityGrant(community *Community, grant []byte, clock uint64) (uint64, error) {
  4540  	_, oldClock, err := m.GetCommunityGrant(community.IDString())
  4541  	if err != nil {
  4542  		return 0, err
  4543  	}
  4544  
  4545  	if oldClock >= clock {
  4546  		return 0, ErrGrantOlder
  4547  	}
  4548  
  4549  	verifiedGrant, err := community.VerifyGrantSignature(grant)
  4550  	if err != nil {
  4551  		return 0, err
  4552  	}
  4553  
  4554  	if !bytes.Equal(verifiedGrant.MemberId, crypto.CompressPubkey(&m.identity.PublicKey)) {
  4555  		return 0, ErrGrantMemberPublicKeyIsDifferent
  4556  	}
  4557  
  4558  	return clock - oldClock, m.persistence.SaveCommunityGrant(community.IDString(), grant, clock)
  4559  }
  4560  
  4561  func (m *Manager) FetchCommunityToken(community *Community, tokenMetadata *protobuf.CommunityTokenMetadata, chainID uint64, contractAddress string) (*community_token.CommunityToken, error) {
  4562  	communityID := community.IDString()
  4563  
  4564  	communityToken := &community_token.CommunityToken{
  4565  		CommunityID:        communityID,
  4566  		Address:            contractAddress,
  4567  		TokenType:          tokenMetadata.TokenType,
  4568  		Name:               tokenMetadata.Name,
  4569  		Symbol:             tokenMetadata.Symbol,
  4570  		Description:        tokenMetadata.Description,
  4571  		Transferable:       true,
  4572  		RemoteSelfDestruct: false,
  4573  		ChainID:            int(chainID),
  4574  		DeployState:        community_token.Deployed,
  4575  		Base64Image:        tokenMetadata.Image,
  4576  		Decimals:           int(tokenMetadata.Decimals),
  4577  		Version:            tokenMetadata.Version,
  4578  	}
  4579  
  4580  	switch tokenMetadata.TokenType {
  4581  	case protobuf.CommunityTokenType_ERC721:
  4582  		contractData, err := m.communityTokensService.GetCollectibleContractData(chainID, contractAddress)
  4583  		if err != nil {
  4584  			return nil, err
  4585  		}
  4586  
  4587  		communityToken.Supply = contractData.TotalSupply
  4588  		communityToken.Transferable = contractData.Transferable
  4589  		communityToken.RemoteSelfDestruct = contractData.RemoteBurnable
  4590  		communityToken.InfiniteSupply = contractData.InfiniteSupply
  4591  
  4592  	case protobuf.CommunityTokenType_ERC20:
  4593  		contractData, err := m.communityTokensService.GetAssetContractData(chainID, contractAddress)
  4594  		if err != nil {
  4595  			return nil, err
  4596  		}
  4597  
  4598  		communityToken.Supply = contractData.TotalSupply
  4599  		communityToken.InfiniteSupply = contractData.InfiniteSupply
  4600  	}
  4601  
  4602  	communityToken.PrivilegesLevel = getPrivilegesLevel(chainID, contractAddress, community.TokenPermissions())
  4603  
  4604  	return communityToken, nil
  4605  }
  4606  
  4607  func getPrivilegesLevel(chainID uint64, tokenAddress string, tokenPermissions map[string]*CommunityTokenPermission) community_token.PrivilegesLevel {
  4608  	for _, permission := range tokenPermissions {
  4609  		if permission.Type == protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER || permission.Type == protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER {
  4610  			for _, tokenCriteria := range permission.TokenCriteria {
  4611  				value, exist := tokenCriteria.ContractAddresses[chainID]
  4612  				if exist && value == tokenAddress {
  4613  					if permission.Type == protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER {
  4614  						return community_token.OwnerLevel
  4615  					}
  4616  					return community_token.MasterLevel
  4617  				}
  4618  			}
  4619  		}
  4620  	}
  4621  	return community_token.CommunityLevel
  4622  }
  4623  
  4624  func (m *Manager) ValidateCommunityPrivilegedUserSyncMessage(message *protobuf.CommunityPrivilegedUserSyncMessage) error {
  4625  	if message == nil {
  4626  		return errors.New("invalid CommunityPrivilegedUserSyncMessage message")
  4627  	}
  4628  
  4629  	if message.CommunityId == nil || len(message.CommunityId) == 0 {
  4630  		return errors.New("invalid CommunityId in CommunityPrivilegedUserSyncMessage message")
  4631  	}
  4632  
  4633  	switch message.Type {
  4634  	case protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ACCEPT_REQUEST_TO_JOIN:
  4635  		fallthrough
  4636  	case protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_REJECT_REQUEST_TO_JOIN:
  4637  		if message.RequestToJoin == nil || len(message.RequestToJoin) == 0 {
  4638  			return errors.New("invalid request to join in CommunityPrivilegedUserSyncMessage message")
  4639  		}
  4640  
  4641  		for _, requestToJoinProto := range message.RequestToJoin {
  4642  			if len(requestToJoinProto.CommunityId) == 0 {
  4643  				return errors.New("no communityId in request to join in CommunityPrivilegedUserSyncMessage message")
  4644  			}
  4645  		}
  4646  	case protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN:
  4647  		if message.SyncRequestsToJoin == nil || len(message.SyncRequestsToJoin) == 0 {
  4648  			return errors.New("invalid sync requests to join in CommunityPrivilegedUserSyncMessage message")
  4649  		}
  4650  	case protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_MEMBER_EDIT_SHARED_ADDRESSES:
  4651  		if message.SyncEditSharedAddresses == nil || len(message.CommunityId) == 0 ||
  4652  			len(message.SyncEditSharedAddresses.PublicKey) == 0 || message.SyncEditSharedAddresses.EditSharedAddress == nil {
  4653  			return errors.New("invalid edit shared adresses in CommunityPrivilegedUserSyncMessage message")
  4654  		}
  4655  	}
  4656  
  4657  	return nil
  4658  }
  4659  
  4660  func (m *Manager) createCommunityTokenPermission(request *requests.CreateCommunityTokenPermission, community *Community) (*Community, *CommunityChanges, error) {
  4661  	if community == nil {
  4662  		return nil, nil, ErrOrgNotFound
  4663  	}
  4664  
  4665  	tokenPermission := request.ToCommunityTokenPermission()
  4666  	tokenPermission.Id = uuid.New().String()
  4667  	changes, err := community.UpsertTokenPermission(&tokenPermission)
  4668  	if err != nil {
  4669  		return nil, nil, err
  4670  	}
  4671  
  4672  	return community, changes, nil
  4673  
  4674  }
  4675  
  4676  func (m *Manager) RemoveUsersWithoutRevealedAccounts(community *Community, clock uint64) (*CommunityChanges, error) {
  4677  	membersAccounts, err := m.persistence.GetCommunityRequestsToJoinRevealedAddresses(community.ID())
  4678  	if err != nil {
  4679  		return nil, err
  4680  	}
  4681  
  4682  	myPk := common.PubkeyToHex(&m.identity.PublicKey)
  4683  	membersToRemove := []string{}
  4684  	for pk := range community.Members() {
  4685  		if myPk == pk {
  4686  			continue
  4687  		}
  4688  		if _, exists := membersAccounts[pk]; !exists {
  4689  			membersToRemove = append(membersToRemove, pk)
  4690  		}
  4691  	}
  4692  
  4693  	if len(membersToRemove) > 0 {
  4694  		community.SetResendAccountsClock(clock)
  4695  	}
  4696  
  4697  	return community.RemoveMembersFromOrg(membersToRemove), nil
  4698  }
  4699  
  4700  func (m *Manager) PromoteSelfToControlNode(community *Community, clock uint64) (*CommunityChanges, error) {
  4701  	if community == nil {
  4702  		return nil, ErrOrgNotFound
  4703  	}
  4704  
  4705  	m.communityLock.Lock(community.ID())
  4706  	defer m.communityLock.Unlock(community.ID())
  4707  
  4708  	ownerChanged, err := m.promoteSelfToControlNode(community, clock)
  4709  	if err != nil {
  4710  		return nil, err
  4711  	}
  4712  
  4713  	if ownerChanged {
  4714  		return community.RemoveAllUsersFromOrg(), m.saveAndPublish(community)
  4715  	}
  4716  
  4717  	// if control node device was changed, check that we own all members revealed accounts
  4718  	// members without revealed accounts will be soft kicked
  4719  	changes, err := m.RemoveUsersWithoutRevealedAccounts(community, clock)
  4720  	if err != nil {
  4721  		return nil, err
  4722  	}
  4723  
  4724  	return changes, m.saveAndPublish(community)
  4725  }
  4726  
  4727  func (m *Manager) promoteSelfToControlNode(community *Community, clock uint64) (bool, error) {
  4728  	ownerChanged := false
  4729  	community.setPrivateKey(m.identity)
  4730  	if !community.ControlNode().Equal(&m.identity.PublicKey) {
  4731  		ownerChanged = true
  4732  		community.setControlNode(&m.identity.PublicKey)
  4733  	}
  4734  
  4735  	// Mark this device as the control node
  4736  	syncControlNode := &protobuf.SyncCommunityControlNode{
  4737  		Clock:          clock,
  4738  		InstallationId: m.installationID,
  4739  	}
  4740  
  4741  	err := m.SaveSyncControlNode(community.ID(), syncControlNode)
  4742  	if err != nil {
  4743  		return false, err
  4744  	}
  4745  	community.config.ControlDevice = true
  4746  
  4747  	if exists := community.HasMember(&m.identity.PublicKey); !exists {
  4748  		ownerRole := []protobuf.CommunityMember_Roles{protobuf.CommunityMember_ROLE_OWNER}
  4749  		_, err = community.AddMember(&m.identity.PublicKey, ownerRole, community.Clock())
  4750  		if err != nil {
  4751  			return false, err
  4752  		}
  4753  
  4754  		for channelID := range community.Chats() {
  4755  			_, err = community.AddMemberToChat(channelID, &m.identity.PublicKey, ownerRole, protobuf.CommunityMember_CHANNEL_ROLE_POSTER)
  4756  			if err != nil {
  4757  				return false, err
  4758  			}
  4759  		}
  4760  	} else {
  4761  		_, err = community.AddRoleToMember(&m.identity.PublicKey, protobuf.CommunityMember_ROLE_OWNER)
  4762  	}
  4763  
  4764  	if err != nil {
  4765  		return false, err
  4766  	}
  4767  
  4768  	err = m.handleCommunityEvents(community)
  4769  	if err != nil {
  4770  		return false, err
  4771  	}
  4772  
  4773  	community.increaseClock()
  4774  
  4775  	return ownerChanged, nil
  4776  }
  4777  
  4778  func (m *Manager) handleCommunityEventsAndMetadata(community *Community, eventsMessage *CommunityEventsMessage,
  4779  	lastlyAppliedEvents map[string]uint64) (*CommunityResponse, error) {
  4780  	err := community.processEvents(eventsMessage, lastlyAppliedEvents)
  4781  	if err != nil {
  4782  		return nil, err
  4783  	}
  4784  
  4785  	additionalCommunityResponse, err := m.handleAdditionalAdminChanges(community)
  4786  	if err != nil {
  4787  		return nil, err
  4788  	}
  4789  
  4790  	if err = m.handleCommunityTokensMetadata(community); err != nil {
  4791  		return nil, err
  4792  	}
  4793  
  4794  	return additionalCommunityResponse, err
  4795  }
  4796  
  4797  func (m *Manager) handleCommunityEvents(community *Community) error {
  4798  	if community.config.EventsData == nil {
  4799  		return nil
  4800  	}
  4801  
  4802  	lastlyAppliedEvents, err := m.persistence.GetAppliedCommunityEvents(community.ID())
  4803  	if err != nil {
  4804  		return err
  4805  	}
  4806  
  4807  	_, err = m.handleCommunityEventsAndMetadata(community, community.toCommunityEventsMessage(), lastlyAppliedEvents)
  4808  	if err != nil {
  4809  		return err
  4810  	}
  4811  
  4812  	appliedEvents := map[string]uint64{}
  4813  	if community.config.EventsData != nil {
  4814  		for _, event := range community.config.EventsData.Events {
  4815  			appliedEvents[event.EventTypeID()] = event.CommunityEventClock
  4816  		}
  4817  	}
  4818  
  4819  	community.config.EventsData = nil // clear events, they are already applied
  4820  	community.increaseClock()
  4821  
  4822  	err = m.persistence.SaveCommunity(community)
  4823  	if err != nil {
  4824  		return err
  4825  	}
  4826  
  4827  	err = m.persistence.UpsertAppliedCommunityEvents(community.ID(), appliedEvents)
  4828  	if err != nil {
  4829  		return err
  4830  	}
  4831  
  4832  	m.publish(&Subscription{Community: community})
  4833  
  4834  	return nil
  4835  }
  4836  
  4837  func (m *Manager) ShareRequestsToJoinWithPrivilegedMembers(community *Community, privilegedMembers map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey) error {
  4838  	if len(privilegedMembers) == 0 {
  4839  		return nil
  4840  	}
  4841  
  4842  	requestsToJoin, err := m.GetCommunityRequestsToJoinWithRevealedAddresses(community.ID())
  4843  	if err != nil {
  4844  		return err
  4845  	}
  4846  
  4847  	var syncRequestsWithoutRevealedAccounts []*protobuf.SyncCommunityRequestsToJoin
  4848  	var syncRequestsWithRevealedAccounts []*protobuf.SyncCommunityRequestsToJoin
  4849  	for _, request := range requestsToJoin {
  4850  		// if shared request to join is not approved by control node - do not send revealed accounts.
  4851  		// revealed accounts will be sent as soon as control node accepts request to join
  4852  		if request.State != RequestToJoinStateAccepted {
  4853  			request.RevealedAccounts = []*protobuf.RevealedAccount{}
  4854  		}
  4855  		syncRequestsWithRevealedAccounts = append(syncRequestsWithRevealedAccounts, request.ToSyncProtobuf())
  4856  		requestProtoWithoutAccounts := request.ToSyncProtobuf()
  4857  		requestProtoWithoutAccounts.RevealedAccounts = []*protobuf.RevealedAccount{}
  4858  		syncRequestsWithoutRevealedAccounts = append(syncRequestsWithoutRevealedAccounts, requestProtoWithoutAccounts)
  4859  	}
  4860  
  4861  	syncMsgWithoutRevealedAccounts := &protobuf.CommunityPrivilegedUserSyncMessage{
  4862  		Type:               protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN,
  4863  		CommunityId:        community.ID(),
  4864  		SyncRequestsToJoin: syncRequestsWithoutRevealedAccounts,
  4865  	}
  4866  
  4867  	syncMsgWitRevealedAccounts := &protobuf.CommunityPrivilegedUserSyncMessage{
  4868  		Type:               protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN,
  4869  		CommunityId:        community.ID(),
  4870  		SyncRequestsToJoin: syncRequestsWithRevealedAccounts,
  4871  	}
  4872  
  4873  	subscriptionMsg := &CommunityPrivilegedMemberSyncMessage{}
  4874  
  4875  	for role, members := range privilegedMembers {
  4876  		if len(members) == 0 {
  4877  			continue
  4878  		}
  4879  
  4880  		subscriptionMsg.Receivers = members
  4881  
  4882  		switch role {
  4883  		case protobuf.CommunityMember_ROLE_ADMIN:
  4884  			subscriptionMsg.CommunityPrivilegedUserSyncMessage = syncMsgWithoutRevealedAccounts
  4885  		case protobuf.CommunityMember_ROLE_OWNER:
  4886  			continue
  4887  		case protobuf.CommunityMember_ROLE_TOKEN_MASTER:
  4888  			subscriptionMsg.CommunityPrivilegedUserSyncMessage = syncMsgWitRevealedAccounts
  4889  		}
  4890  
  4891  		m.publish(&Subscription{CommunityPrivilegedMemberSyncMessage: subscriptionMsg})
  4892  	}
  4893  
  4894  	return nil
  4895  }
  4896  
  4897  func (m *Manager) shareAcceptedRequestToJoinWithPrivilegedMembers(community *Community, requestsToJoin *RequestToJoin) error {
  4898  	pk, err := common.HexToPubkey(requestsToJoin.PublicKey)
  4899  	if err != nil {
  4900  		return err
  4901  	}
  4902  
  4903  	acceptedRequestsToJoinWithoutRevealedAccounts := make(map[string]*protobuf.CommunityRequestToJoin)
  4904  	acceptedRequestsToJoinWithRevealedAccounts := make(map[string]*protobuf.CommunityRequestToJoin)
  4905  
  4906  	acceptedRequestsToJoinWithRevealedAccounts[requestsToJoin.PublicKey] = requestsToJoin.ToCommunityRequestToJoinProtobuf()
  4907  	requestsToJoin.RevealedAccounts = make([]*protobuf.RevealedAccount, 0)
  4908  	acceptedRequestsToJoinWithoutRevealedAccounts[requestsToJoin.PublicKey] = requestsToJoin.ToCommunityRequestToJoinProtobuf()
  4909  
  4910  	msgWithRevealedAccounts := &protobuf.CommunityPrivilegedUserSyncMessage{
  4911  		Type:          protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ACCEPT_REQUEST_TO_JOIN,
  4912  		CommunityId:   community.ID(),
  4913  		RequestToJoin: acceptedRequestsToJoinWithRevealedAccounts,
  4914  	}
  4915  
  4916  	msgWithoutRevealedAccounts := &protobuf.CommunityPrivilegedUserSyncMessage{
  4917  		Type:          protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ACCEPT_REQUEST_TO_JOIN,
  4918  		CommunityId:   community.ID(),
  4919  		RequestToJoin: acceptedRequestsToJoinWithoutRevealedAccounts,
  4920  	}
  4921  
  4922  	// do not sent to ourself and to the accepted user
  4923  	skipMembers := make(map[string]struct{})
  4924  	skipMembers[common.PubkeyToHex(&m.identity.PublicKey)] = struct{}{}
  4925  	skipMembers[common.PubkeyToHex(pk)] = struct{}{}
  4926  
  4927  	subscriptionMsg := &CommunityPrivilegedMemberSyncMessage{}
  4928  
  4929  	fileredPrivilegedMembers := community.GetFilteredPrivilegedMembers(skipMembers)
  4930  	for role, members := range fileredPrivilegedMembers {
  4931  		if len(members) == 0 {
  4932  			continue
  4933  		}
  4934  
  4935  		subscriptionMsg.Receivers = members
  4936  
  4937  		switch role {
  4938  		case protobuf.CommunityMember_ROLE_ADMIN:
  4939  			subscriptionMsg.CommunityPrivilegedUserSyncMessage = msgWithoutRevealedAccounts
  4940  		case protobuf.CommunityMember_ROLE_OWNER:
  4941  			fallthrough
  4942  		case protobuf.CommunityMember_ROLE_TOKEN_MASTER:
  4943  			subscriptionMsg.CommunityPrivilegedUserSyncMessage = msgWithRevealedAccounts
  4944  		}
  4945  
  4946  		m.publish(&Subscription{CommunityPrivilegedMemberSyncMessage: subscriptionMsg})
  4947  	}
  4948  
  4949  	return nil
  4950  }
  4951  
  4952  func (m *Manager) GetCommunityRequestsToJoinWithRevealedAddresses(communityID types.HexBytes) ([]*RequestToJoin, error) {
  4953  	return m.persistence.GetCommunityRequestsToJoinWithRevealedAddresses(communityID)
  4954  }
  4955  
  4956  func (m *Manager) SaveCommunity(community *Community) error {
  4957  	return m.persistence.SaveCommunity(community)
  4958  }
  4959  
  4960  func (m *Manager) CreateCommunityTokenDeploymentSignature(ctx context.Context, chainID uint64, addressFrom string, communityID string) ([]byte, error) {
  4961  	community, err := m.GetByIDString(communityID)
  4962  	if err != nil {
  4963  		return nil, err
  4964  	}
  4965  	if !community.IsControlNode() {
  4966  		return nil, ErrNotControlNode
  4967  	}
  4968  	digest, err := m.communityTokensService.DeploymentSignatureDigest(chainID, addressFrom, communityID)
  4969  	if err != nil {
  4970  		return nil, err
  4971  	}
  4972  	return crypto.Sign(digest, community.PrivateKey())
  4973  }
  4974  
  4975  func (m *Manager) GetSyncControlNode(id types.HexBytes) (*protobuf.SyncCommunityControlNode, error) {
  4976  	return m.persistence.GetSyncControlNode(id)
  4977  }
  4978  
  4979  func (m *Manager) SaveSyncControlNode(id types.HexBytes, syncControlNode *protobuf.SyncCommunityControlNode) error {
  4980  	return m.persistence.SaveSyncControlNode(id, syncControlNode.Clock, syncControlNode.InstallationId)
  4981  }
  4982  
  4983  func (m *Manager) SetSyncControlNode(id types.HexBytes, syncControlNode *protobuf.SyncCommunityControlNode) error {
  4984  	existingSyncControlNode, err := m.GetSyncControlNode(id)
  4985  	if err != nil {
  4986  		return err
  4987  	}
  4988  
  4989  	if existingSyncControlNode == nil || existingSyncControlNode.Clock < syncControlNode.Clock {
  4990  		return m.SaveSyncControlNode(id, syncControlNode)
  4991  	}
  4992  
  4993  	return nil
  4994  }
  4995  
  4996  func (m *Manager) GetCommunityRequestToJoinWithRevealedAddresses(pubKey string, communityID types.HexBytes) (*RequestToJoin, error) {
  4997  	return m.persistence.GetCommunityRequestToJoinWithRevealedAddresses(pubKey, communityID)
  4998  }
  4999  
  5000  func (m *Manager) SafeGetSignerPubKey(chainID uint64, communityID string) (string, error) {
  5001  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
  5002  	defer cancel()
  5003  
  5004  	return m.ownerVerifier.SafeGetSignerPubKey(ctx, chainID, communityID)
  5005  }
  5006  
  5007  func (m *Manager) GetCuratedCommunities() (*CuratedCommunities, error) {
  5008  	return m.persistence.GetCuratedCommunities()
  5009  }
  5010  
  5011  func (m *Manager) SetCuratedCommunities(communities *CuratedCommunities) error {
  5012  	return m.persistence.SetCuratedCommunities(communities)
  5013  }
  5014  
  5015  func (m *Manager) encryptCommunityDescriptionImpl(groupID []byte, d *protobuf.CommunityDescription) (string, []byte, error) {
  5016  	payload, err := proto.Marshal(d)
  5017  	if err != nil {
  5018  		return "", nil, err
  5019  	}
  5020  
  5021  	encryptedPayload, ratchet, newSeqNo, err := m.encryptor.EncryptWithHashRatchet(groupID, payload)
  5022  	if err == encryption.ErrNoEncryptionKey {
  5023  		_, err := m.encryptor.GenerateHashRatchetKey(groupID)
  5024  		if err != nil {
  5025  			return "", nil, err
  5026  		}
  5027  		encryptedPayload, ratchet, newSeqNo, err = m.encryptor.EncryptWithHashRatchet(groupID, payload)
  5028  		if err != nil {
  5029  			return "", nil, err
  5030  		}
  5031  
  5032  	} else if err != nil {
  5033  		return "", nil, err
  5034  	}
  5035  
  5036  	keyID, err := ratchet.GetKeyID()
  5037  	if err != nil {
  5038  		return "", nil, err
  5039  	}
  5040  
  5041  	m.logger.Debug("encrypting community description",
  5042  		zap.Any("community", d),
  5043  		zap.String("groupID", types.Bytes2Hex(groupID)),
  5044  		zap.String("keyID", types.Bytes2Hex(keyID)))
  5045  
  5046  	keyIDSeqNo := fmt.Sprintf("%s%d", hex.EncodeToString(keyID), newSeqNo)
  5047  
  5048  	return keyIDSeqNo, encryptedPayload, nil
  5049  }
  5050  
  5051  func (m *Manager) encryptCommunityDescription(community *Community, d *protobuf.CommunityDescription) (string, []byte, error) {
  5052  	return m.encryptCommunityDescriptionImpl(community.ID(), d)
  5053  }
  5054  
  5055  func (m *Manager) encryptCommunityDescriptionChannel(community *Community, channelID string, d *protobuf.CommunityDescription) (string, []byte, error) {
  5056  	return m.encryptCommunityDescriptionImpl([]byte(community.IDString()+channelID), d)
  5057  }
  5058  
  5059  // TODO: add collectiblesManager to messenger intance
  5060  func (m *Manager) GetCollectiblesManager() CollectiblesManager {
  5061  	return m.collectiblesManager
  5062  }
  5063  
  5064  type DecryptCommunityResponse struct {
  5065  	Decrypted   bool
  5066  	Description *protobuf.CommunityDescription
  5067  	KeyID       []byte
  5068  	GroupID     []byte
  5069  }
  5070  
  5071  func (m *Manager) decryptCommunityDescription(keyIDSeqNo string, d []byte) (*DecryptCommunityResponse, error) {
  5072  	const hashHexLength = 64
  5073  	if len(keyIDSeqNo) <= hashHexLength {
  5074  		return nil, errors.New("invalid keyIDSeqNo")
  5075  	}
  5076  
  5077  	keyID, err := hex.DecodeString(keyIDSeqNo[:hashHexLength])
  5078  	if err != nil {
  5079  		return nil, err
  5080  	}
  5081  
  5082  	seqNo, err := strconv.ParseUint(keyIDSeqNo[hashHexLength:], 10, 32)
  5083  	if err != nil {
  5084  		return nil, err
  5085  	}
  5086  
  5087  	decryptedPayload, err := m.encryptor.DecryptWithHashRatchet(keyID, uint32(seqNo), d)
  5088  	if err == encryption.ErrNoRatchetKey {
  5089  		return &DecryptCommunityResponse{
  5090  			KeyID: keyID,
  5091  		}, err
  5092  
  5093  	}
  5094  	if err != nil {
  5095  		return nil, err
  5096  	}
  5097  
  5098  	var description protobuf.CommunityDescription
  5099  	err = proto.Unmarshal(decryptedPayload, &description)
  5100  	if err != nil {
  5101  		return nil, err
  5102  	}
  5103  
  5104  	decryptCommunityResponse := &DecryptCommunityResponse{
  5105  		Decrypted:   true,
  5106  		KeyID:       keyID,
  5107  		Description: &description,
  5108  	}
  5109  	return decryptCommunityResponse, nil
  5110  }
  5111  
  5112  // GetPersistence returns the instantiated *Persistence used by the Manager
  5113  func (m *Manager) GetPersistence() *Persistence {
  5114  	return m.persistence
  5115  }
  5116  
  5117  func ToLinkPreveiwThumbnail(image images.IdentityImage) (*common.LinkPreviewThumbnail, error) {
  5118  	thumbnail := &common.LinkPreviewThumbnail{}
  5119  
  5120  	if image.IsEmpty() {
  5121  		return nil, nil
  5122  	}
  5123  
  5124  	width, height, err := images.GetImageDimensions(image.Payload)
  5125  	if err != nil {
  5126  		return nil, fmt.Errorf("failed to get image dimensions: %w", err)
  5127  	}
  5128  
  5129  	dataURI, err := image.GetDataURI()
  5130  	if err != nil {
  5131  		return nil, fmt.Errorf("failed to get data uri: %w", err)
  5132  	}
  5133  
  5134  	thumbnail.Width = width
  5135  	thumbnail.Height = height
  5136  	thumbnail.DataURI = dataURI
  5137  	return thumbnail, nil
  5138  }
  5139  
  5140  func (c *Community) ToStatusLinkPreview() (*common.StatusCommunityLinkPreview, error) {
  5141  	communityLinkPreview := &common.StatusCommunityLinkPreview{}
  5142  	if image, ok := c.Images()[images.SmallDimName]; ok {
  5143  		thumbnail, err := ToLinkPreveiwThumbnail(images.IdentityImage{Payload: image.Payload})
  5144  		if err != nil {
  5145  			c.config.Logger.Warn("unfurling status link: failed to set community thumbnail", zap.Error(err))
  5146  		}
  5147  		communityLinkPreview.Icon = *thumbnail
  5148  	}
  5149  
  5150  	if image, ok := c.Images()[images.BannerIdentityName]; ok {
  5151  		thumbnail, err := ToLinkPreveiwThumbnail(images.IdentityImage{Payload: image.Payload})
  5152  		if err != nil {
  5153  			c.config.Logger.Warn("unfurling status link: failed to set community thumbnail", zap.Error(err))
  5154  		}
  5155  		communityLinkPreview.Banner = *thumbnail
  5156  	}
  5157  
  5158  	communityLinkPreview.CommunityID = c.IDString()
  5159  	communityLinkPreview.DisplayName = c.Name()
  5160  	communityLinkPreview.Description = c.DescriptionText()
  5161  	communityLinkPreview.MembersCount = uint32(c.MembersCount())
  5162  	communityLinkPreview.Color = c.Color()
  5163  
  5164  	return communityLinkPreview, nil
  5165  }
  5166  
  5167  func (m *Manager) determineChannelsForHRKeysRequest(c *Community, now int64) ([]string, error) {
  5168  	result := []string{}
  5169  
  5170  	channelsWithMissingKeys := func() map[string]struct{} {
  5171  		r := map[string]struct{}{}
  5172  		for id := range c.Chats() {
  5173  			if c.HasMissingEncryptionKey(id) {
  5174  				r[id] = struct{}{}
  5175  			}
  5176  		}
  5177  		return r
  5178  	}()
  5179  
  5180  	if len(channelsWithMissingKeys) == 0 {
  5181  		return result, nil
  5182  	}
  5183  
  5184  	requests, err := m.persistence.GetEncryptionKeyRequests(c.ID(), channelsWithMissingKeys)
  5185  	if err != nil {
  5186  		return nil, err
  5187  	}
  5188  
  5189  	for channelID := range channelsWithMissingKeys {
  5190  		request, ok := requests[channelID]
  5191  		if !ok {
  5192  			// If there's no prior request, ask for encryption key now
  5193  			result = append(result, channelID)
  5194  			continue
  5195  		}
  5196  
  5197  		// Exponential backoff formula: initial delay * 2^(requestCount - 1)
  5198  		initialDelay := int64(10 * 60 * 1000) // 10 minutes in milliseconds
  5199  		backoffDuration := initialDelay * (1 << (request.requestedCount - 1))
  5200  		nextRequestTime := request.requestedAt + backoffDuration
  5201  
  5202  		if now >= nextRequestTime {
  5203  			result = append(result, channelID)
  5204  		}
  5205  	}
  5206  
  5207  	return result, nil
  5208  }
  5209  
  5210  type CommunityWithChannelIDs struct {
  5211  	Community  *Community
  5212  	ChannelIDs []string
  5213  }
  5214  
  5215  // DetermineChannelsForHRKeysRequest identifies channels in a community that
  5216  // should ask for encryption keys based on their current state and past request records,
  5217  // as determined by exponential backoff.
  5218  func (m *Manager) DetermineChannelsForHRKeysRequest() ([]*CommunityWithChannelIDs, error) {
  5219  	communities, err := m.Joined()
  5220  	if err != nil {
  5221  		return nil, err
  5222  	}
  5223  
  5224  	result := []*CommunityWithChannelIDs{}
  5225  	now := time.Now().UnixMilli()
  5226  
  5227  	for _, c := range communities {
  5228  		if c.IsControlNode() {
  5229  			continue
  5230  		}
  5231  
  5232  		channelsToRequest, err := m.determineChannelsForHRKeysRequest(c, now)
  5233  		if err != nil {
  5234  			return nil, err
  5235  		}
  5236  
  5237  		if len(channelsToRequest) > 0 {
  5238  			result = append(result, &CommunityWithChannelIDs{
  5239  				Community:  c,
  5240  				ChannelIDs: channelsToRequest,
  5241  			})
  5242  		}
  5243  	}
  5244  
  5245  	return result, nil
  5246  }
  5247  
  5248  func (m *Manager) updateEncryptionKeysRequests(communityID types.HexBytes, channelIDs []string, now int64) error {
  5249  	return m.persistence.UpdateAndPruneEncryptionKeyRequests(communityID, channelIDs, now)
  5250  }
  5251  
  5252  func (m *Manager) UpdateEncryptionKeysRequests(communityID types.HexBytes, channelIDs []string) error {
  5253  	return m.updateEncryptionKeysRequests(communityID, channelIDs, time.Now().UnixMilli())
  5254  }