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

     1  package communities
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"math"
    10  	"math/big"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/golang/protobuf/proto"
    15  	"go.uber.org/zap"
    16  	slices "golang.org/x/exp/slices"
    17  
    18  	"github.com/ethereum/go-ethereum/common/hexutil"
    19  
    20  	"github.com/status-im/status-go/api/multiformat"
    21  	utils "github.com/status-im/status-go/common"
    22  	"github.com/status-im/status-go/eth-node/crypto"
    23  	"github.com/status-im/status-go/eth-node/types"
    24  	"github.com/status-im/status-go/images"
    25  	"github.com/status-im/status-go/protocol/common"
    26  	"github.com/status-im/status-go/protocol/common/shard"
    27  	community_token "github.com/status-im/status-go/protocol/communities/token"
    28  	"github.com/status-im/status-go/protocol/protobuf"
    29  	"github.com/status-im/status-go/protocol/requests"
    30  	"github.com/status-im/status-go/protocol/v1"
    31  	"github.com/status-im/status-go/server"
    32  )
    33  
    34  const signatureLength = 65
    35  
    36  // GrantExpirationTime interval of 7 days
    37  var GrantExpirationTime = 168 * time.Hour
    38  
    39  type Config struct {
    40  	PrivateKey                          *ecdsa.PrivateKey
    41  	ControlNode                         *ecdsa.PublicKey
    42  	ControlDevice                       bool // whether this device is control node
    43  	CommunityDescription                *protobuf.CommunityDescription
    44  	CommunityDescriptionProtocolMessage []byte // community in a wrapped & signed (by owner) protocol message
    45  	ID                                  *ecdsa.PublicKey
    46  	Joined                              bool
    47  	JoinedAt                            int64
    48  	Requested                           bool
    49  	Verified                            bool
    50  	Spectated                           bool
    51  	Muted                               bool
    52  	MuteTill                            time.Time
    53  	Logger                              *zap.Logger
    54  	RequestedToJoinAt                   uint64
    55  	RequestsToJoin                      []*RequestToJoin
    56  	MemberIdentity                      *ecdsa.PrivateKey
    57  	EventsData                          *EventsData
    58  	Shard                               *shard.Shard
    59  	PubsubTopicPrivateKey               *ecdsa.PrivateKey
    60  	LastOpenedAt                        int64
    61  }
    62  
    63  type EventsData struct {
    64  	EventsBaseCommunityDescription []byte
    65  	Events                         []CommunityEvent
    66  }
    67  
    68  type Community struct {
    69  	config      *Config
    70  	mutex       sync.Mutex
    71  	timesource  common.TimeSource
    72  	encryptor   DescriptionEncryptor
    73  	mediaServer server.MediaServerInterface
    74  }
    75  
    76  func New(config Config, timesource common.TimeSource, encryptor DescriptionEncryptor, mediaServer server.MediaServerInterface) (*Community, error) {
    77  	if config.MemberIdentity == nil {
    78  		return nil, errors.New("no member identity")
    79  	}
    80  
    81  	if timesource == nil {
    82  		return nil, errors.New("no timesource")
    83  	}
    84  
    85  	if config.Logger == nil {
    86  		logger, err := zap.NewDevelopment()
    87  		if err != nil {
    88  			return nil, err
    89  		}
    90  		config.Logger = logger
    91  	}
    92  
    93  	if config.CommunityDescription == nil {
    94  		config.CommunityDescription = &protobuf.CommunityDescription{}
    95  	}
    96  
    97  	return &Community{
    98  		config:      &config,
    99  		timesource:  timesource,
   100  		encryptor:   encryptor,
   101  		mediaServer: mediaServer,
   102  	}, nil
   103  }
   104  
   105  type CommunityAdminSettings struct {
   106  	PinMessageAllMembersEnabled bool `json:"pinMessageAllMembersEnabled"`
   107  }
   108  
   109  type CommunityChat struct {
   110  	ID                      string                               `json:"id"`
   111  	Name                    string                               `json:"name"`
   112  	Color                   string                               `json:"color"`
   113  	Emoji                   string                               `json:"emoji"`
   114  	Description             string                               `json:"description"`
   115  	Members                 map[string]*protobuf.CommunityMember `json:"members"`
   116  	Permissions             *protobuf.CommunityPermissions       `json:"permissions"`
   117  	CanPost                 bool                                 `json:"canPost"`
   118  	CanView                 bool                                 `json:"canView"`
   119  	CanPostReactions        bool                                 `json:"canPostReactions"`
   120  	ViewersCanPostReactions bool                                 `json:"viewersCanPostReactions"`
   121  	Position                int                                  `json:"position"`
   122  	CategoryID              string                               `json:"categoryID"`
   123  	TokenGated              bool                                 `json:"tokenGated"`
   124  	HideIfPermissionsNotMet bool                                 `json:"hideIfPermissionsNotMet"`
   125  	MissingEncryptionKey    bool                                 `json:"missingEncryptionKey"`
   126  }
   127  
   128  type CommunityCategory struct {
   129  	ID       string `json:"id"`
   130  	Name     string `json:"name"`
   131  	Position int    `json:"position"` // Position is used to sort the categories
   132  }
   133  
   134  type CommunityTag struct {
   135  	Name  string `json:"name"`
   136  	Emoji string `json:"emoji"`
   137  }
   138  
   139  type CommunityMemberState uint8
   140  
   141  const (
   142  	CommunityMemberBanned CommunityMemberState = iota
   143  	CommunityMemberBanPending
   144  	CommunityMemberUnbanPending
   145  	CommunityMemberKickPending
   146  	CommunityMemberBanWithAllMessagesDelete
   147  )
   148  
   149  func (o *Community) MarshalPublicAPIJSON() ([]byte, error) {
   150  	if o.config.MemberIdentity == nil {
   151  		return nil, errors.New("member identity not set")
   152  	}
   153  	communityItem := struct {
   154  		ID                      types.HexBytes                       `json:"id"`
   155  		Verified                bool                                 `json:"verified"`
   156  		Chats                   map[string]CommunityChat             `json:"chats"`
   157  		Categories              map[string]CommunityCategory         `json:"categories"`
   158  		Name                    string                               `json:"name"`
   159  		Description             string                               `json:"description"`
   160  		IntroMessage            string                               `json:"introMessage"`
   161  		OutroMessage            string                               `json:"outroMessage"`
   162  		Tags                    []CommunityTag                       `json:"tags"`
   163  		Images                  map[string]images.IdentityImage      `json:"images"`
   164  		Color                   string                               `json:"color"`
   165  		MembersCount            int                                  `json:"membersCount"`
   166  		EnsName                 string                               `json:"ensName"`
   167  		Link                    string                               `json:"link"`
   168  		CommunityAdminSettings  CommunityAdminSettings               `json:"adminSettings"`
   169  		Encrypted               bool                                 `json:"encrypted"`
   170  		TokenPermissions        map[string]*CommunityTokenPermission `json:"tokenPermissions"`
   171  		CommunityTokensMetadata []*protobuf.CommunityTokenMetadata   `json:"communityTokensMetadata"`
   172  		ActiveMembersCount      uint64                               `json:"activeMembersCount"`
   173  		PubsubTopic             string                               `json:"pubsubTopic"`
   174  		PubsubTopicKey          string                               `json:"pubsubTopicKey"`
   175  		Shard                   *shard.Shard                         `json:"shard"`
   176  	}{
   177  		ID:             o.ID(),
   178  		Verified:       o.config.Verified,
   179  		Chats:          make(map[string]CommunityChat),
   180  		Categories:     make(map[string]CommunityCategory),
   181  		Tags:           o.Tags(),
   182  		PubsubTopic:    o.PubsubTopic(),
   183  		PubsubTopicKey: o.PubsubTopicKey(),
   184  		Shard:          o.Shard(),
   185  	}
   186  
   187  	if o.config.CommunityDescription != nil {
   188  		for id, c := range o.config.CommunityDescription.Categories {
   189  			category := CommunityCategory{
   190  				ID:       id,
   191  				Name:     c.Name,
   192  				Position: int(c.Position),
   193  			}
   194  			communityItem.Categories[id] = category
   195  			communityItem.Encrypted = o.Encrypted()
   196  		}
   197  		for id, c := range o.config.CommunityDescription.Chats {
   198  			// NOTE: Here `CanPost` is only set for ChatMessage and Emoji reactions. But it can be different for pin/etc.
   199  			// Consider adding more properties to `CommunityChat` to reflect that.
   200  			canPost, err := o.CanPost(o.MemberIdentity(), id, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
   201  			if err != nil {
   202  				return nil, err
   203  			}
   204  			canPostReactions, err := o.CanPost(o.MemberIdentity(), id, protobuf.ApplicationMetadataMessage_EMOJI_REACTION)
   205  			if err != nil {
   206  				return nil, err
   207  			}
   208  			canView := o.CanView(o.MemberIdentity(), id)
   209  
   210  			chat := CommunityChat{
   211  				ID:                      id,
   212  				Name:                    c.Identity.DisplayName,
   213  				Color:                   c.Identity.Color,
   214  				Emoji:                   c.Identity.Emoji,
   215  				Description:             c.Identity.Description,
   216  				Permissions:             c.Permissions,
   217  				Members:                 c.Members,
   218  				CanPost:                 canPost,
   219  				CanView:                 canView,
   220  				CanPostReactions:        canPostReactions,
   221  				ViewersCanPostReactions: c.ViewersCanPostReactions,
   222  				TokenGated:              o.channelEncrypted(id),
   223  				CategoryID:              c.CategoryId,
   224  				HideIfPermissionsNotMet: c.HideIfPermissionsNotMet,
   225  				Position:                int(c.Position),
   226  			}
   227  			communityItem.Chats[id] = chat
   228  		}
   229  
   230  		communityItem.TokenPermissions = o.tokenPermissions()
   231  		communityItem.MembersCount = len(o.config.CommunityDescription.Members)
   232  
   233  		communityItem.Link = fmt.Sprintf("https://join.status.im/c/0x%x", o.ID())
   234  		if o.Shard() != nil {
   235  			communityItem.Link = fmt.Sprintf("%s/%d/%d", communityItem.Link, o.Shard().Cluster, o.Shard().Index)
   236  		}
   237  
   238  		communityItem.IntroMessage = o.config.CommunityDescription.IntroMessage
   239  		communityItem.OutroMessage = o.config.CommunityDescription.OutroMessage
   240  		communityItem.CommunityTokensMetadata = o.config.CommunityDescription.CommunityTokensMetadata
   241  		communityItem.ActiveMembersCount = o.config.CommunityDescription.ActiveMembersCount
   242  
   243  		if o.config.CommunityDescription.Identity != nil {
   244  			communityItem.Name = o.Name()
   245  			communityItem.Color = o.config.CommunityDescription.Identity.Color
   246  			communityItem.Description = o.config.CommunityDescription.Identity.Description
   247  			for t, i := range o.config.CommunityDescription.Identity.Images {
   248  				if communityItem.Images == nil {
   249  					communityItem.Images = make(map[string]images.IdentityImage)
   250  				}
   251  				communityItem.Images[t] = images.IdentityImage{Name: t, Payload: i.Payload}
   252  
   253  			}
   254  		}
   255  
   256  		communityItem.CommunityAdminSettings = CommunityAdminSettings{
   257  			PinMessageAllMembersEnabled: false,
   258  		}
   259  
   260  		if o.config.CommunityDescription.AdminSettings != nil {
   261  			communityItem.CommunityAdminSettings.PinMessageAllMembersEnabled = o.config.CommunityDescription.AdminSettings.PinMessageAllMembersEnabled
   262  		}
   263  	}
   264  	return json.Marshal(communityItem)
   265  }
   266  
   267  func (o *Community) MarshalJSON() ([]byte, error) {
   268  	if o.config.MemberIdentity == nil {
   269  		return nil, errors.New("member identity not set")
   270  	}
   271  
   272  	type Image struct {
   273  		Uri string `json:"uri"`
   274  	}
   275  	communityItem := struct {
   276  		ID                          types.HexBytes                       `json:"id"`
   277  		MemberRole                  protobuf.CommunityMember_Roles       `json:"memberRole"`
   278  		IsControlNode               bool                                 `json:"isControlNode"`
   279  		Verified                    bool                                 `json:"verified"`
   280  		Joined                      bool                                 `json:"joined"`
   281  		JoinedAt                    int64                                `json:"joinedAt"`
   282  		Spectated                   bool                                 `json:"spectated"`
   283  		RequestedAccessAt           int                                  `json:"requestedAccessAt"`
   284  		Name                        string                               `json:"name"`
   285  		Description                 string                               `json:"description"`
   286  		IntroMessage                string                               `json:"introMessage"`
   287  		OutroMessage                string                               `json:"outroMessage"`
   288  		Tags                        []CommunityTag                       `json:"tags"`
   289  		Chats                       map[string]CommunityChat             `json:"chats"`
   290  		Categories                  map[string]CommunityCategory         `json:"categories"`
   291  		Images                      map[string]Image                     `json:"images"`
   292  		Permissions                 *protobuf.CommunityPermissions       `json:"permissions"`
   293  		Members                     map[string]*protobuf.CommunityMember `json:"members"`
   294  		CanRequestAccess            bool                                 `json:"canRequestAccess"`
   295  		CanManageUsers              bool                                 `json:"canManageUsers"`              //TODO: we can remove this
   296  		CanDeleteMessageForEveryone bool                                 `json:"canDeleteMessageForEveryone"` //TODO: we can remove this
   297  		CanJoin                     bool                                 `json:"canJoin"`
   298  		Color                       string                               `json:"color"`
   299  		RequestedToJoinAt           uint64                               `json:"requestedToJoinAt,omitempty"`
   300  		IsMember                    bool                                 `json:"isMember"`
   301  		Muted                       bool                                 `json:"muted"`
   302  		MuteTill                    time.Time                            `json:"muteTill,omitempty"`
   303  		CommunityAdminSettings      CommunityAdminSettings               `json:"adminSettings"`
   304  		Encrypted                   bool                                 `json:"encrypted"`
   305  		PendingAndBannedMembers     map[string]CommunityMemberState      `json:"pendingAndBannedMembers"`
   306  		TokenPermissions            map[string]*CommunityTokenPermission `json:"tokenPermissions"`
   307  		CommunityTokensMetadata     []*protobuf.CommunityTokenMetadata   `json:"communityTokensMetadata"`
   308  		ActiveMembersCount          uint64                               `json:"activeMembersCount"`
   309  		PubsubTopic                 string                               `json:"pubsubTopic"`
   310  		PubsubTopicKey              string                               `json:"pubsubTopicKey"`
   311  		Shard                       *shard.Shard                         `json:"shard"`
   312  		LastOpenedAt                int64                                `json:"lastOpenedAt"`
   313  		Clock                       uint64                               `json:"clock"`
   314  	}{
   315  		ID:                          o.ID(),
   316  		Clock:                       o.Clock(),
   317  		MemberRole:                  o.MemberRole(o.MemberIdentity()),
   318  		IsControlNode:               o.IsControlNode(),
   319  		Verified:                    o.config.Verified,
   320  		Chats:                       make(map[string]CommunityChat),
   321  		Categories:                  make(map[string]CommunityCategory),
   322  		Joined:                      o.config.Joined,
   323  		JoinedAt:                    o.config.JoinedAt,
   324  		Spectated:                   o.config.Spectated,
   325  		CanRequestAccess:            o.CanRequestAccess(o.MemberIdentity()),
   326  		CanJoin:                     o.canJoin(),
   327  		CanManageUsers:              o.CanManageUsers(o.MemberIdentity()),
   328  		CanDeleteMessageForEveryone: o.CanDeleteMessageForEveryone(o.MemberIdentity()),
   329  		RequestedToJoinAt:           o.RequestedToJoinAt(),
   330  		IsMember:                    o.isMember(),
   331  		Muted:                       o.config.Muted,
   332  		MuteTill:                    o.config.MuteTill,
   333  		Tags:                        o.Tags(),
   334  		Encrypted:                   o.Encrypted(),
   335  		PubsubTopic:                 o.PubsubTopic(),
   336  		PubsubTopicKey:              o.PubsubTopicKey(),
   337  		Shard:                       o.Shard(),
   338  		LastOpenedAt:                o.config.LastOpenedAt,
   339  	}
   340  	if o.config.CommunityDescription != nil {
   341  		for id, c := range o.config.CommunityDescription.Categories {
   342  			category := CommunityCategory{
   343  				ID:       id,
   344  				Name:     c.Name,
   345  				Position: int(c.Position),
   346  			}
   347  			communityItem.Encrypted = o.Encrypted()
   348  			communityItem.Categories[id] = category
   349  		}
   350  		for id, c := range o.config.CommunityDescription.Chats {
   351  			// NOTE: Here `CanPost` is only set for ChatMessage. But it can be different for reactions/pin/etc.
   352  			// Consider adding more properties to `CommunityChat` to reflect that.
   353  			canPost, err := o.CanPost(o.MemberIdentity(), id, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
   354  			if err != nil {
   355  				return nil, err
   356  			}
   357  			canPostReactions, err := o.CanPost(o.MemberIdentity(), id, protobuf.ApplicationMetadataMessage_EMOJI_REACTION)
   358  			if err != nil {
   359  				return nil, err
   360  			}
   361  			canView := o.CanView(o.MemberIdentity(), id)
   362  
   363  			chat := CommunityChat{
   364  				ID:                      id,
   365  				Name:                    c.Identity.DisplayName,
   366  				Emoji:                   c.Identity.Emoji,
   367  				Color:                   c.Identity.Color,
   368  				Description:             c.Identity.Description,
   369  				Permissions:             c.Permissions,
   370  				CanPost:                 canPost,
   371  				CanView:                 canView,
   372  				CanPostReactions:        canPostReactions,
   373  				ViewersCanPostReactions: c.ViewersCanPostReactions,
   374  				TokenGated:              o.channelEncrypted(id),
   375  				CategoryID:              c.CategoryId,
   376  				HideIfPermissionsNotMet: c.HideIfPermissionsNotMet,
   377  				Position:                int(c.Position),
   378  				MissingEncryptionKey:    o.HasMissingEncryptionKey(id),
   379  			}
   380  
   381  			if chat.TokenGated {
   382  				chat.Members = c.Members
   383  			}
   384  			communityItem.Chats[id] = chat
   385  		}
   386  		communityItem.TokenPermissions = o.tokenPermissions()
   387  		communityItem.PendingAndBannedMembers = o.PendingAndBannedMembers()
   388  		communityItem.Members = o.config.CommunityDescription.Members
   389  		communityItem.Permissions = o.config.CommunityDescription.Permissions
   390  		communityItem.IntroMessage = o.config.CommunityDescription.IntroMessage
   391  		communityItem.OutroMessage = o.config.CommunityDescription.OutroMessage
   392  
   393  		// update token meta image to url rather than base64 image
   394  		var tokenMetadata []*protobuf.CommunityTokenMetadata
   395  
   396  		if !utils.IsNil(o.mediaServer) {
   397  			for _, m := range o.config.CommunityDescription.CommunityTokensMetadata {
   398  				copyM := proto.Clone(m).(*protobuf.CommunityTokenMetadata)
   399  				copyM.Image = o.mediaServer.MakeCommunityDescriptionTokenImageURL(o.IDString(), copyM.GetSymbol())
   400  				tokenMetadata = append(tokenMetadata, copyM)
   401  			}
   402  			communityItem.CommunityTokensMetadata = tokenMetadata
   403  		}
   404  		communityItem.ActiveMembersCount = o.config.CommunityDescription.ActiveMembersCount
   405  
   406  		if o.config.CommunityDescription.Identity != nil {
   407  			communityItem.Name = o.Name()
   408  			communityItem.Color = o.config.CommunityDescription.Identity.Color
   409  			communityItem.Description = o.config.CommunityDescription.Identity.Description
   410  
   411  			if !utils.IsNil(o.mediaServer) {
   412  				for t := range o.config.CommunityDescription.Identity.Images {
   413  					if communityItem.Images == nil {
   414  						communityItem.Images = make(map[string]Image)
   415  					}
   416  					communityItem.Images[t] = Image{Uri: o.mediaServer.MakeCommunityImageURL(o.IDString(), t)}
   417  				}
   418  			}
   419  		}
   420  
   421  		communityItem.CommunityAdminSettings = CommunityAdminSettings{
   422  			PinMessageAllMembersEnabled: false,
   423  		}
   424  
   425  		if o.config.CommunityDescription.AdminSettings != nil {
   426  			communityItem.CommunityAdminSettings.PinMessageAllMembersEnabled = o.config.CommunityDescription.AdminSettings.PinMessageAllMembersEnabled
   427  		}
   428  	}
   429  	return json.Marshal(communityItem)
   430  }
   431  
   432  func (o *Community) Identity() *protobuf.ChatIdentity {
   433  	return o.config.CommunityDescription.Identity
   434  }
   435  
   436  func (o *Community) Permissions() *protobuf.CommunityPermissions {
   437  	return o.config.CommunityDescription.Permissions
   438  }
   439  
   440  func (o *Community) AdminSettings() *protobuf.CommunityAdminSettings {
   441  	return o.config.CommunityDescription.AdminSettings
   442  }
   443  
   444  func (o *Community) Name() string {
   445  	if o != nil &&
   446  		o.config != nil &&
   447  		o.config.CommunityDescription != nil &&
   448  		o.config.CommunityDescription.Identity != nil {
   449  		return o.config.CommunityDescription.Identity.DisplayName
   450  	}
   451  	return ""
   452  }
   453  
   454  func (o *Community) DescriptionText() string {
   455  	if o != nil &&
   456  		o.config != nil &&
   457  		o.config.CommunityDescription != nil &&
   458  		o.config.CommunityDescription.Identity != nil {
   459  		return o.config.CommunityDescription.Identity.Description
   460  	}
   461  	return ""
   462  }
   463  
   464  func (o *Community) Shard() *shard.Shard {
   465  	if o != nil && o.config != nil {
   466  		return o.config.Shard
   467  	}
   468  
   469  	return nil
   470  }
   471  
   472  func (o *Community) CommunityShard() CommunityShard {
   473  	return CommunityShard{
   474  		CommunityID: o.IDString(),
   475  		Shard:       o.Shard(),
   476  	}
   477  }
   478  
   479  func (o *Community) IntroMessage() string {
   480  	if o != nil &&
   481  		o.config != nil &&
   482  		o.config.CommunityDescription != nil {
   483  		return o.config.CommunityDescription.IntroMessage
   484  	}
   485  	return ""
   486  }
   487  
   488  func (o *Community) CommunityTokensMetadata() []*protobuf.CommunityTokenMetadata {
   489  	if o != nil &&
   490  		o.config != nil &&
   491  		o.config.CommunityDescription != nil {
   492  		return o.config.CommunityDescription.CommunityTokensMetadata
   493  	}
   494  	return nil
   495  }
   496  
   497  func (o *Community) Tags() []CommunityTag {
   498  	if o == nil ||
   499  		o.config == nil ||
   500  		o.config.CommunityDescription == nil {
   501  		return nil
   502  	}
   503  
   504  	result := make([]CommunityTag, 0, len(o.config.CommunityDescription.Tags))
   505  	for _, t := range o.config.CommunityDescription.Tags {
   506  		result = append(result, CommunityTag{
   507  			Name:  t,
   508  			Emoji: requests.TagEmoji(t),
   509  		})
   510  	}
   511  	return result
   512  }
   513  
   514  func (o *Community) TagsRaw() []string {
   515  	return o.config.CommunityDescription.Tags
   516  }
   517  
   518  func (o *Community) TagsIndices() []uint32 {
   519  	var indices []uint32
   520  	for _, t := range o.config.CommunityDescription.Tags {
   521  		indices = append(indices, requests.TagIndex(t))
   522  	}
   523  	return indices
   524  }
   525  
   526  func (o *Community) OutroMessage() string {
   527  	if o != nil &&
   528  		o.config != nil &&
   529  		o.config.CommunityDescription != nil {
   530  		return o.config.CommunityDescription.OutroMessage
   531  	}
   532  	return ""
   533  }
   534  
   535  func (o *Community) Color() string {
   536  	if o != nil &&
   537  		o.config != nil &&
   538  		o.config.CommunityDescription != nil &&
   539  		o.config.CommunityDescription.Identity != nil {
   540  		return o.config.CommunityDescription.Identity.Color
   541  	}
   542  	return ""
   543  }
   544  
   545  func (o *Community) Members() map[string]*protobuf.CommunityMember {
   546  	if o != nil &&
   547  		o.config != nil &&
   548  		o.config.CommunityDescription != nil {
   549  		return o.config.CommunityDescription.Members
   550  	}
   551  	return nil
   552  }
   553  
   554  func (o *Community) UpdateMemberLastUpdateClock(publicKey string, clock uint64) {
   555  	o.mutex.Lock()
   556  	defer o.mutex.Unlock()
   557  
   558  	if member, exists := o.config.CommunityDescription.Members[publicKey]; exists {
   559  		member.LastUpdateClock = clock
   560  	}
   561  }
   562  
   563  func (o *Community) MembersCount() int {
   564  	if o != nil &&
   565  		o.config != nil &&
   566  		o.config.CommunityDescription != nil {
   567  		return len(o.config.CommunityDescription.Members)
   568  	}
   569  	return 0
   570  }
   571  
   572  func (o *Community) GetMemberPubkeys() []*ecdsa.PublicKey {
   573  	if o != nil &&
   574  		o.config != nil &&
   575  		o.config.CommunityDescription != nil {
   576  		pubkeys := make([]*ecdsa.PublicKey, len(o.config.CommunityDescription.Members))
   577  		i := 0
   578  		for hex := range o.config.CommunityDescription.Members {
   579  			pubkeys[i], _ = common.HexToPubkey(hex)
   580  			i++
   581  		}
   582  		return pubkeys
   583  	}
   584  	return nil
   585  }
   586  
   587  type CommunitySettings struct {
   588  	CommunityID                  string `json:"communityId"`
   589  	HistoryArchiveSupportEnabled bool   `json:"historyArchiveSupportEnabled"`
   590  	Clock                        uint64 `json:"clock"`
   591  }
   592  
   593  func (o *Community) emptyCommunityChanges() *CommunityChanges {
   594  	changes := EmptyCommunityChanges()
   595  	changes.Community = o
   596  	return changes
   597  }
   598  
   599  func (o *Community) CreateChat(chatID string, chat *protobuf.CommunityChat) (*CommunityChanges, error) {
   600  	o.mutex.Lock()
   601  	defer o.mutex.Unlock()
   602  
   603  	if !(o.IsControlNode() || o.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_CHANNEL_CREATE)) {
   604  		return nil, ErrNotAuthorized
   605  	}
   606  
   607  	err := o.createChat(chatID, chat)
   608  	if err != nil {
   609  		return nil, err
   610  	}
   611  	changes := o.emptyCommunityChanges()
   612  	changes.ChatsAdded[chatID] = chat
   613  
   614  	if o.IsControlNode() {
   615  		o.increaseClock()
   616  	} else {
   617  		err := o.addNewCommunityEvent(o.ToCreateChannelCommunityEvent(chatID, chat))
   618  		if err != nil {
   619  			return nil, err
   620  		}
   621  	}
   622  
   623  	return changes, nil
   624  }
   625  
   626  func (o *Community) EditChat(chatID string, chat *protobuf.CommunityChat) (*CommunityChanges, error) {
   627  	o.mutex.Lock()
   628  	defer o.mutex.Unlock()
   629  
   630  	if !(o.IsControlNode() || o.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_CHANNEL_EDIT)) {
   631  		return nil, ErrNotAuthorized
   632  	}
   633  
   634  	err := o.editChat(chatID, chat)
   635  	if err != nil {
   636  		return nil, err
   637  	}
   638  	changes := o.emptyCommunityChanges()
   639  	changes.ChatsModified[chatID] = &CommunityChatChanges{
   640  		ChatModified: chat,
   641  	}
   642  
   643  	if o.IsControlNode() {
   644  		o.increaseClock()
   645  	} else {
   646  		err := o.addNewCommunityEvent(o.ToEditChannelCommunityEvent(chatID, chat))
   647  		if err != nil {
   648  			return nil, err
   649  		}
   650  	}
   651  
   652  	return changes, nil
   653  }
   654  
   655  func (o *Community) DeleteChat(chatID string) (*CommunityChanges, error) {
   656  	o.mutex.Lock()
   657  	defer o.mutex.Unlock()
   658  
   659  	if !(o.IsControlNode() || o.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_CHANNEL_DELETE)) {
   660  		return nil, ErrNotAuthorized
   661  	}
   662  
   663  	changes := o.deleteChat(chatID)
   664  
   665  	if o.IsControlNode() {
   666  		o.increaseClock()
   667  	} else {
   668  		err := o.addNewCommunityEvent(o.ToDeleteChannelCommunityEvent(chatID))
   669  		if err != nil {
   670  			return nil, err
   671  		}
   672  	}
   673  
   674  	return changes, nil
   675  }
   676  
   677  func (o *Community) getMember(pk *ecdsa.PublicKey) *protobuf.CommunityMember {
   678  
   679  	key := common.PubkeyToHex(pk)
   680  	member := o.config.CommunityDescription.Members[key]
   681  	return member
   682  }
   683  
   684  func (o *Community) GetMember(pk *ecdsa.PublicKey) *protobuf.CommunityMember {
   685  	return o.getMember(pk)
   686  }
   687  
   688  func (o *Community) GetChat(chatID string) (*protobuf.CommunityChat, error) {
   689  	chat, ok := o.config.CommunityDescription.Chats[chatID]
   690  	if !ok {
   691  		return nil, ErrChatNotFound
   692  	}
   693  
   694  	return chat, nil
   695  }
   696  
   697  func (o *Community) getChatMember(pk *ecdsa.PublicKey, chatID string) *protobuf.CommunityMember {
   698  	if !o.hasMember(pk) {
   699  		return nil
   700  	}
   701  
   702  	chat, ok := o.config.CommunityDescription.Chats[chatID]
   703  	if !ok {
   704  		return nil
   705  	}
   706  
   707  	key := common.PubkeyToHex(pk)
   708  	return chat.Members[key]
   709  }
   710  
   711  func (o *Community) hasMember(pk *ecdsa.PublicKey) bool {
   712  
   713  	member := o.getMember(pk)
   714  	return member != nil
   715  }
   716  
   717  func (o *Community) IsBanned(pk *ecdsa.PublicKey) bool {
   718  	o.mutex.Lock()
   719  	defer o.mutex.Unlock()
   720  	return o.isBanned(pk)
   721  }
   722  
   723  func (o *Community) isBanned(pk *ecdsa.PublicKey) bool {
   724  
   725  	key := common.PubkeyToHex(pk)
   726  
   727  	banned := slices.Contains(o.config.CommunityDescription.BanList, key)
   728  
   729  	if o.config.CommunityDescription.BannedMembers != nil && !banned {
   730  		_, banned = o.config.CommunityDescription.BannedMembers[key]
   731  	}
   732  
   733  	return banned
   734  
   735  }
   736  
   737  func (o *Community) rolesOf(pk *ecdsa.PublicKey) []protobuf.CommunityMember_Roles {
   738  	member := o.getMember(pk)
   739  	if member == nil {
   740  		return nil
   741  	}
   742  
   743  	return member.Roles
   744  }
   745  
   746  func (o *Community) memberHasRoles(member *protobuf.CommunityMember, roles map[protobuf.CommunityMember_Roles]bool) bool {
   747  	for _, r := range member.Roles {
   748  		if roles[r] {
   749  			return true
   750  		}
   751  	}
   752  	return false
   753  }
   754  
   755  func (o *Community) hasRoles(pk *ecdsa.PublicKey, roles map[protobuf.CommunityMember_Roles]bool) bool {
   756  	if pk == nil || o.config == nil || o.config.ID == nil {
   757  		return false
   758  	}
   759  
   760  	member := o.getMember(pk)
   761  	if member == nil {
   762  		return false
   763  	}
   764  
   765  	return o.memberHasRoles(member, roles)
   766  }
   767  
   768  func (o *Community) HasMember(pk *ecdsa.PublicKey) bool {
   769  	o.mutex.Lock()
   770  	defer o.mutex.Unlock()
   771  	return o.hasMember(pk)
   772  }
   773  
   774  func (o *Community) isMemberInChat(pk *ecdsa.PublicKey, chatID string) bool {
   775  	return o.getChatMember(pk, chatID) != nil
   776  }
   777  
   778  func (o *Community) IsMemberInChat(pk *ecdsa.PublicKey, chatID string) bool {
   779  	o.mutex.Lock()
   780  	defer o.mutex.Unlock()
   781  
   782  	return o.isMemberInChat(pk, chatID)
   783  }
   784  
   785  // Uses bloom filter members list to estimate presence in the channel.
   786  // False positive rate is 0.1%.
   787  func (o *Community) IsMemberLikelyInChat(chatID string) bool {
   788  	if o.IsControlNode() || o.IsPrivilegedMember(o.MemberIdentity()) || !o.channelEncrypted(chatID) {
   789  		return true
   790  	}
   791  
   792  	chat, ok := o.config.CommunityDescription.Chats[chatID]
   793  	if !ok {
   794  		return false
   795  	}
   796  
   797  	// For communities controlled by clients that haven't updated to newer version yet we assume no membership.
   798  	if chat.MembersList == nil {
   799  		return false
   800  	}
   801  
   802  	res, err := verifyMembershipWithBloomFilter(chat.MembersList, o.config.MemberIdentity, o.ControlNode(), chatID, o.Clock())
   803  	if err != nil {
   804  		o.config.Logger.Error("failed to estimate membership", zap.Error(err))
   805  		return false
   806  	}
   807  
   808  	return res
   809  }
   810  
   811  func (o *Community) RemoveUserFromChat(pk *ecdsa.PublicKey, chatID string) (*protobuf.CommunityDescription, error) {
   812  	o.mutex.Lock()
   813  	defer o.mutex.Unlock()
   814  
   815  	if !o.IsControlNode() {
   816  		return nil, ErrNotControlNode
   817  	}
   818  	if !o.hasMember(pk) {
   819  		return o.config.CommunityDescription, nil
   820  	}
   821  
   822  	chat, ok := o.config.CommunityDescription.Chats[chatID]
   823  	if !ok {
   824  		return o.config.CommunityDescription, nil
   825  	}
   826  
   827  	key := common.PubkeyToHex(pk)
   828  	delete(chat.Members, key)
   829  
   830  	if o.IsControlNode() {
   831  		o.increaseClock()
   832  	}
   833  
   834  	return o.config.CommunityDescription, nil
   835  }
   836  
   837  func (o *Community) RemoveOurselvesFromOrg(pk *ecdsa.PublicKey) {
   838  	o.mutex.Lock()
   839  	defer o.mutex.Unlock()
   840  	_ = o.RemoveMembersFromOrg([]string{common.PubkeyToHex(pk)})
   841  	o.increaseClock()
   842  }
   843  
   844  func (o *Community) RemoveUserFromOrg(pk *ecdsa.PublicKey) (*protobuf.CommunityDescription, error) {
   845  	o.mutex.Lock()
   846  	defer o.mutex.Unlock()
   847  
   848  	if !(o.IsControlNode() || o.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK)) {
   849  		return nil, ErrNotAuthorized
   850  	}
   851  
   852  	if !o.IsControlNode() && o.IsPrivilegedMember(pk) {
   853  		return nil, ErrCannotRemoveOwnerOrAdmin
   854  	}
   855  
   856  	pkStr := common.PubkeyToHex(pk)
   857  
   858  	if o.IsControlNode() {
   859  		_ = o.RemoveMembersFromOrg([]string{pkStr})
   860  		o.increaseClock()
   861  	} else {
   862  		err := o.addNewCommunityEvent(o.ToKickCommunityMemberCommunityEvent(common.PubkeyToHex(pk)))
   863  		if err != nil {
   864  			return nil, err
   865  		}
   866  	}
   867  
   868  	return o.config.CommunityDescription, nil
   869  }
   870  
   871  func (o *Community) RemoveMembersFromOrg(membersToRemove []string) *CommunityChanges {
   872  	changes := o.emptyCommunityChanges()
   873  
   874  	if len(membersToRemove) == 0 {
   875  		return changes
   876  	}
   877  
   878  	for _, pk := range membersToRemove {
   879  		member, exists := o.config.CommunityDescription.Members[pk]
   880  		if exists {
   881  			changes.MembersRemoved[pk] = member
   882  			delete(o.config.CommunityDescription.Members, pk)
   883  		}
   884  	}
   885  
   886  	if len(changes.MembersRemoved) == 0 {
   887  		return changes
   888  	}
   889  
   890  	for chatID, chat := range o.config.CommunityDescription.Chats {
   891  		chatMembersToRemove := make(map[string]*protobuf.CommunityMember)
   892  		for _, pk := range membersToRemove {
   893  			chatMember, exists := chat.Members[pk]
   894  			if exists {
   895  				chatMembersToRemove[pk] = chatMember
   896  				delete(chat.Members, pk)
   897  			}
   898  		}
   899  
   900  		changes.ChatsModified[chatID] = &CommunityChatChanges{
   901  			ChatModified:   chat,
   902  			MembersRemoved: chatMembersToRemove,
   903  		}
   904  	}
   905  
   906  	return changes
   907  }
   908  
   909  func (o *Community) RemoveAllUsersFromOrg() *CommunityChanges {
   910  	o.increaseClock()
   911  
   912  	myPublicKey := common.PubkeyToHex(o.MemberIdentity())
   913  	member := o.config.CommunityDescription.Members[myPublicKey]
   914  
   915  	membersToRemove := o.config.CommunityDescription.Members
   916  	delete(membersToRemove, myPublicKey)
   917  
   918  	changes := o.emptyCommunityChanges()
   919  	changes.MembersRemoved = membersToRemove
   920  
   921  	o.config.CommunityDescription.Members = make(map[string]*protobuf.CommunityMember)
   922  	o.config.CommunityDescription.Members[myPublicKey] = member
   923  
   924  	for chatID, chat := range o.config.CommunityDescription.Chats {
   925  		chatMembersToRemove := chat.Members
   926  		delete(chatMembersToRemove, myPublicKey)
   927  
   928  		chat.Members = make(map[string]*protobuf.CommunityMember)
   929  		chat.Members[myPublicKey] = member
   930  
   931  		changes.ChatsModified[chatID] = &CommunityChatChanges{
   932  			ChatModified:   chat,
   933  			MembersRemoved: chatMembersToRemove,
   934  		}
   935  	}
   936  
   937  	return changes
   938  }
   939  
   940  func (o *Community) AddCommunityTokensMetadata(token *protobuf.CommunityTokenMetadata) (*protobuf.CommunityDescription, error) {
   941  	o.mutex.Lock()
   942  	defer o.mutex.Unlock()
   943  
   944  	if !(o.IsControlNode() || o.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_TOKEN_ADD)) {
   945  		return nil, ErrNotAuthorized
   946  	}
   947  
   948  	o.config.CommunityDescription.CommunityTokensMetadata = append(o.config.CommunityDescription.CommunityTokensMetadata, token)
   949  
   950  	if o.IsControlNode() {
   951  		o.increaseClock()
   952  	} else {
   953  		err := o.addNewCommunityEvent(o.ToAddTokenMetadataCommunityEvent(token))
   954  		if err != nil {
   955  			return nil, err
   956  		}
   957  	}
   958  
   959  	return o.config.CommunityDescription, nil
   960  }
   961  
   962  func containsToken(tokens []*protobuf.CommunityTokenMetadata, symbol string) bool {
   963  	for _, token := range tokens {
   964  		if token.Symbol == symbol {
   965  			return true
   966  		}
   967  	}
   968  	return false
   969  }
   970  
   971  func (o *Community) UpsertCommunityTokensMetadata(token *protobuf.CommunityTokenMetadata) (bool, error) {
   972  	if containsToken(o.config.CommunityDescription.CommunityTokensMetadata, token.Symbol) {
   973  		return false, nil
   974  	}
   975  
   976  	_, err := o.AddCommunityTokensMetadata(token)
   977  	return true, err
   978  }
   979  
   980  func (o *Community) UnbanUserFromCommunity(pk *ecdsa.PublicKey) (*protobuf.CommunityDescription, error) {
   981  	o.mutex.Lock()
   982  	defer o.mutex.Unlock()
   983  
   984  	if !(o.IsControlNode() || o.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN)) {
   985  		return nil, ErrNotAuthorized
   986  	}
   987  
   988  	if o.IsControlNode() {
   989  		o.unbanUserFromCommunity(pk)
   990  		o.increaseClock()
   991  	} else {
   992  		err := o.addNewCommunityEvent(o.ToUnbanCommunityMemberCommunityEvent(common.PubkeyToHex(pk)))
   993  		if err != nil {
   994  			return nil, err
   995  		}
   996  	}
   997  
   998  	return o.config.CommunityDescription, nil
   999  }
  1000  
  1001  func (o *Community) BanUserFromCommunity(pk *ecdsa.PublicKey, communityBanInfo *protobuf.CommunityBanInfo) (*protobuf.CommunityDescription, error) {
  1002  	o.mutex.Lock()
  1003  	defer o.mutex.Unlock()
  1004  
  1005  	if !(o.IsControlNode() || o.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN)) {
  1006  		return nil, ErrNotAuthorized
  1007  	}
  1008  
  1009  	if !o.IsControlNode() && o.IsPrivilegedMember(pk) {
  1010  		return nil, ErrCannotBanOwnerOrAdmin
  1011  	}
  1012  
  1013  	if o.IsControlNode() {
  1014  		o.banUserFromCommunity(pk, communityBanInfo)
  1015  		o.increaseClock()
  1016  	} else {
  1017  		pkStr := common.PubkeyToHex(pk)
  1018  		err := o.addNewCommunityEvent(o.ToBanCommunityMemberCommunityEvent(pkStr))
  1019  		if err != nil {
  1020  			return nil, err
  1021  		}
  1022  		if communityBanInfo.DeleteAllMessages {
  1023  			err := o.addNewCommunityEvent(o.ToDeleteAllMemberMessagesEvent(pkStr))
  1024  			if err != nil {
  1025  				return nil, err
  1026  			}
  1027  		}
  1028  	}
  1029  
  1030  	return o.config.CommunityDescription, nil
  1031  }
  1032  
  1033  func (o *Community) setRoleToMember(pk *ecdsa.PublicKey, role protobuf.CommunityMember_Roles, setter func(member *protobuf.CommunityMember, role protobuf.CommunityMember_Roles) bool) (*protobuf.CommunityDescription, error) {
  1034  	updated := false
  1035  
  1036  	member := o.getMember(pk)
  1037  	if member != nil {
  1038  		updated = setter(member, role)
  1039  	}
  1040  
  1041  	for channelID := range o.chats() {
  1042  		chatMember := o.getChatMember(pk, channelID)
  1043  		if chatMember != nil {
  1044  			_ = setter(member, role)
  1045  		}
  1046  	}
  1047  
  1048  	if updated {
  1049  		o.increaseClock()
  1050  	}
  1051  
  1052  	return o.config.CommunityDescription, nil
  1053  }
  1054  
  1055  func (o *Community) SetRoleToMember(pk *ecdsa.PublicKey, role protobuf.CommunityMember_Roles) (*protobuf.CommunityDescription, error) {
  1056  	if !o.IsControlNode() {
  1057  		return nil, ErrNotControlNode
  1058  	}
  1059  	o.mutex.Lock()
  1060  	defer o.mutex.Unlock()
  1061  
  1062  	setRole := func(member *protobuf.CommunityMember, role protobuf.CommunityMember_Roles) bool {
  1063  		if len(member.Roles) == 1 && member.Roles[0] == role {
  1064  			return false
  1065  		}
  1066  		member.Roles = []protobuf.CommunityMember_Roles{role}
  1067  		return true
  1068  	}
  1069  
  1070  	return o.setRoleToMember(pk, role, setRole)
  1071  }
  1072  
  1073  // Deprecated: roles are mutually exclusive, use SetRoleToMember instead.
  1074  func (o *Community) AddRoleToMember(pk *ecdsa.PublicKey, role protobuf.CommunityMember_Roles) (*protobuf.CommunityDescription, error) {
  1075  	if !o.IsControlNode() {
  1076  		return nil, ErrNotControlNode
  1077  	}
  1078  	o.mutex.Lock()
  1079  	defer o.mutex.Unlock()
  1080  
  1081  	addRole := func(member *protobuf.CommunityMember, role protobuf.CommunityMember_Roles) bool {
  1082  		roles := make(map[protobuf.CommunityMember_Roles]bool)
  1083  		roles[role] = true
  1084  		if !o.memberHasRoles(member, roles) {
  1085  			member.Roles = append(member.Roles, role)
  1086  			return true
  1087  		}
  1088  		return false
  1089  	}
  1090  
  1091  	return o.setRoleToMember(pk, role, addRole)
  1092  }
  1093  
  1094  func (o *Community) RemoveRoleFromMember(pk *ecdsa.PublicKey, role protobuf.CommunityMember_Roles) (*protobuf.CommunityDescription, error) {
  1095  	o.mutex.Lock()
  1096  	defer o.mutex.Unlock()
  1097  
  1098  	if !o.IsControlNode() {
  1099  		return nil, ErrNotControlNode
  1100  	}
  1101  
  1102  	updated := false
  1103  	removeRole := func(member *protobuf.CommunityMember) {
  1104  		roles := make(map[protobuf.CommunityMember_Roles]bool)
  1105  		roles[role] = true
  1106  		if o.memberHasRoles(member, roles) {
  1107  			var newRoles []protobuf.CommunityMember_Roles
  1108  			for _, r := range member.Roles {
  1109  				if r != role {
  1110  					newRoles = append(newRoles, r)
  1111  				}
  1112  			}
  1113  			member.Roles = newRoles
  1114  			updated = true
  1115  		}
  1116  	}
  1117  
  1118  	member := o.getMember(pk)
  1119  	if member != nil {
  1120  		removeRole(member)
  1121  	}
  1122  
  1123  	for channelID := range o.chats() {
  1124  		chatMember := o.getChatMember(pk, channelID)
  1125  		if chatMember != nil {
  1126  			removeRole(member)
  1127  		}
  1128  	}
  1129  
  1130  	if updated {
  1131  		o.increaseClock()
  1132  	}
  1133  	return o.config.CommunityDescription, nil
  1134  }
  1135  
  1136  func (o *Community) Edit(description *protobuf.CommunityDescription) {
  1137  	o.config.CommunityDescription.Identity.DisplayName = description.Identity.DisplayName
  1138  	o.config.CommunityDescription.Identity.Description = description.Identity.Description
  1139  	o.config.CommunityDescription.Identity.Color = description.Identity.Color
  1140  	o.config.CommunityDescription.Tags = description.Tags
  1141  	o.config.CommunityDescription.Identity.Emoji = description.Identity.Emoji
  1142  	o.config.CommunityDescription.Identity.Images = description.Identity.Images
  1143  	o.config.CommunityDescription.IntroMessage = description.IntroMessage
  1144  	o.config.CommunityDescription.OutroMessage = description.OutroMessage
  1145  	if o.config.CommunityDescription.AdminSettings == nil {
  1146  		o.config.CommunityDescription.AdminSettings = &protobuf.CommunityAdminSettings{}
  1147  	}
  1148  	o.config.CommunityDescription.Permissions = description.Permissions
  1149  	o.config.CommunityDescription.AdminSettings.PinMessageAllMembersEnabled = description.AdminSettings.PinMessageAllMembersEnabled
  1150  }
  1151  
  1152  func (o *Community) EditPermissionAccess(permissionAccess protobuf.CommunityPermissions_Access) {
  1153  	o.config.CommunityDescription.Permissions.Access = permissionAccess
  1154  	if o.IsControlNode() {
  1155  		o.increaseClock()
  1156  	}
  1157  }
  1158  
  1159  func (o *Community) Join() {
  1160  	o.config.Joined = true
  1161  	o.config.JoinedAt = time.Now().Unix()
  1162  	o.config.Spectated = false
  1163  }
  1164  
  1165  func (o *Community) UpdateLastOpenedAt(timestamp int64) {
  1166  	o.config.LastOpenedAt = timestamp
  1167  }
  1168  
  1169  func (o *Community) Leave() {
  1170  	o.config.Joined = false
  1171  	o.config.Spectated = false
  1172  }
  1173  
  1174  func (o *Community) Spectate() {
  1175  	o.config.Spectated = true
  1176  }
  1177  
  1178  func (o *Community) Encrypted() bool {
  1179  	return len(o.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_MEMBER)) > 0
  1180  }
  1181  
  1182  func (o *Community) Joined() bool {
  1183  	return o.config.Joined
  1184  }
  1185  
  1186  func (o *Community) JoinedAt() int64 {
  1187  	return o.config.JoinedAt
  1188  }
  1189  
  1190  func (o *Community) LastOpenedAt() int64 {
  1191  	return o.config.LastOpenedAt
  1192  }
  1193  
  1194  func (o *Community) Spectated() bool {
  1195  	return o.config.Spectated
  1196  }
  1197  
  1198  func (o *Community) Verified() bool {
  1199  	return o.config.Verified
  1200  }
  1201  
  1202  func (o *Community) Muted() bool {
  1203  	return o.config.Muted
  1204  }
  1205  
  1206  func (o *Community) MuteTill() time.Time {
  1207  	return o.config.MuteTill
  1208  }
  1209  
  1210  func (o *Community) MemberIdentity() *ecdsa.PublicKey {
  1211  	return &o.config.MemberIdentity.PublicKey
  1212  }
  1213  
  1214  // UpdateCommunityDescription will update the community to the new community description and return a list of changes
  1215  func (o *Community) UpdateCommunityDescription(description *protobuf.CommunityDescription, rawMessage []byte, newControlNode *ecdsa.PublicKey) (*CommunityChanges, error) {
  1216  	o.mutex.Lock()
  1217  	defer o.mutex.Unlock()
  1218  
  1219  	// This is done in case tags are updated and a client sends unknown tags
  1220  	description.Tags = requests.RemoveUnknownAndDeduplicateTags(description.Tags)
  1221  
  1222  	err := ValidateCommunityDescription(description)
  1223  	if err != nil {
  1224  		return nil, err
  1225  	}
  1226  
  1227  	// Enables processing of identical clocks. Identical descriptions may be reprocessed upon subsequent receipt of the previously missing encryption key.
  1228  	if description.Clock < o.config.CommunityDescription.Clock {
  1229  		return nil, ErrInvalidCommunityDescriptionClockOutdated
  1230  	}
  1231  
  1232  	originCommunity := o.CreateDeepCopy()
  1233  
  1234  	o.config.CommunityDescription = description
  1235  	o.config.CommunityDescriptionProtocolMessage = rawMessage
  1236  
  1237  	if newControlNode != nil {
  1238  		o.setControlNode(newControlNode)
  1239  	}
  1240  
  1241  	response := o.emptyCommunityChanges()
  1242  
  1243  	// We only calculate changes if we joined/spectated the community or we requested access, otherwise not interested
  1244  	if o.config.Joined || o.config.Spectated || o.config.RequestedToJoinAt > 0 {
  1245  		response = EvaluateCommunityChanges(originCommunity, o)
  1246  	}
  1247  
  1248  	return response, nil
  1249  }
  1250  
  1251  func (o *Community) UpdateChatFirstMessageTimestamp(chatID string, timestamp uint32) (*CommunityChanges, error) {
  1252  	if !o.IsControlNode() {
  1253  		return nil, ErrNotControlNode
  1254  	}
  1255  
  1256  	chat, ok := o.config.CommunityDescription.Chats[chatID]
  1257  	if !ok {
  1258  		return nil, ErrChatNotFound
  1259  	}
  1260  
  1261  	chat.Identity.FirstMessageTimestamp = timestamp
  1262  
  1263  	communityChanges := o.emptyCommunityChanges()
  1264  	communityChanges.ChatsModified[chatID] = &CommunityChatChanges{
  1265  		FirstMessageTimestampModified: timestamp,
  1266  	}
  1267  	return communityChanges, nil
  1268  }
  1269  
  1270  // ValidateRequestToJoin validates a request, checks that the right permissions are applied
  1271  func (o *Community) ValidateRequestToJoin(signer *ecdsa.PublicKey, request *protobuf.CommunityRequestToJoin) error {
  1272  	o.mutex.Lock()
  1273  	defer o.mutex.Unlock()
  1274  
  1275  	if o.IsControlNode() {
  1276  		if len(request.RevealedAccounts) == 0 {
  1277  			return errors.New("no addresses revealed")
  1278  		}
  1279  	} else if o.HasPermissionToSendCommunityEvents() {
  1280  		if o.AutoAccept() {
  1281  			return errors.New("auto-accept community requests can only be processed by the control node")
  1282  		}
  1283  	} else {
  1284  		return ErrNotAdmin
  1285  	}
  1286  
  1287  	if o.config.CommunityDescription.Permissions.EnsOnly && len(request.EnsName) == 0 {
  1288  		return ErrCantRequestAccess
  1289  	}
  1290  
  1291  	if len(request.ChatId) != 0 {
  1292  		return o.validateRequestToJoinWithChatID(request)
  1293  	}
  1294  
  1295  	err := o.validateRequestToJoinWithoutChatID(request)
  1296  	if err != nil {
  1297  		return err
  1298  	}
  1299  
  1300  	if o.isBanned(signer) {
  1301  		return ErrCantRequestAccess
  1302  	}
  1303  
  1304  	timeNow := uint64(time.Now().Unix())
  1305  	requestTimeOutClock, err := AddTimeoutToRequestToJoinClock(request.Clock)
  1306  	if err != nil {
  1307  		return err
  1308  	}
  1309  	if timeNow >= requestTimeOutClock {
  1310  		return errors.New("request is expired")
  1311  	}
  1312  
  1313  	return nil
  1314  }
  1315  
  1316  // ValidateRequestToJoin validates a request, checks that the right permissions are applied
  1317  func (o *Community) ValidateEditSharedAddresses(signer string, request *protobuf.CommunityEditSharedAddresses) error {
  1318  	o.mutex.Lock()
  1319  	defer o.mutex.Unlock()
  1320  
  1321  	if len(request.RevealedAccounts) == 0 {
  1322  		return errors.New("no addresses were shared")
  1323  	}
  1324  
  1325  	member, exists := o.config.CommunityDescription.Members[signer]
  1326  	if !exists {
  1327  		return errors.New("signer is not a community member")
  1328  	}
  1329  
  1330  	if request.Clock < member.LastUpdateClock {
  1331  		return ErrEditSharedAddressesRequestOutdated
  1332  	}
  1333  
  1334  	return nil
  1335  }
  1336  
  1337  // We treat control node as an owner with community key
  1338  func (o *Community) IsControlNode() bool {
  1339  	return o.config.PrivateKey != nil && o.config.PrivateKey.PublicKey.Equal(o.ControlNode()) && o.config.ControlDevice
  1340  }
  1341  
  1342  func (o *Community) IsOwner() bool {
  1343  	return o.IsMemberOwner(o.MemberIdentity())
  1344  }
  1345  
  1346  func (o *Community) IsTokenMaster() bool {
  1347  	return o.IsMemberTokenMaster(o.MemberIdentity())
  1348  }
  1349  
  1350  func (o *Community) IsAdmin() bool {
  1351  	return o.IsMemberAdmin(o.MemberIdentity())
  1352  }
  1353  
  1354  func (o *Community) GetTokenMasterMembers() []*ecdsa.PublicKey {
  1355  	tokenMasterMembers := make([]*ecdsa.PublicKey, 0)
  1356  	members := o.GetMemberPubkeys()
  1357  	for _, member := range members {
  1358  		if o.IsMemberTokenMaster(member) {
  1359  			tokenMasterMembers = append(tokenMasterMembers, member)
  1360  		}
  1361  	}
  1362  	return tokenMasterMembers
  1363  }
  1364  
  1365  func (o *Community) GetPrivilegedMembers() []*ecdsa.PublicKey {
  1366  	privilegedMembers := make([]*ecdsa.PublicKey, 0)
  1367  	members := o.GetMemberPubkeys()
  1368  	for _, member := range members {
  1369  		if o.IsPrivilegedMember(member) {
  1370  			privilegedMembers = append(privilegedMembers, member)
  1371  		}
  1372  	}
  1373  	return privilegedMembers
  1374  }
  1375  
  1376  func (o *Community) GetFilteredPrivilegedMembers(skipMembers map[string]struct{}) map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey {
  1377  	privilegedMembers := make(map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey)
  1378  	privilegedMembers[protobuf.CommunityMember_ROLE_TOKEN_MASTER] = []*ecdsa.PublicKey{}
  1379  	privilegedMembers[protobuf.CommunityMember_ROLE_ADMIN] = []*ecdsa.PublicKey{}
  1380  	privilegedMembers[protobuf.CommunityMember_ROLE_OWNER] = []*ecdsa.PublicKey{}
  1381  
  1382  	members := o.GetMemberPubkeys()
  1383  	for _, member := range members {
  1384  		if len(skipMembers) > 0 {
  1385  			if _, exist := skipMembers[common.PubkeyToHex(member)]; exist {
  1386  				delete(skipMembers, common.PubkeyToHex(member))
  1387  				continue
  1388  			}
  1389  		}
  1390  
  1391  		memberRole := o.MemberRole(member)
  1392  		if memberRole == protobuf.CommunityMember_ROLE_OWNER || memberRole == protobuf.CommunityMember_ROLE_ADMIN ||
  1393  			memberRole == protobuf.CommunityMember_ROLE_TOKEN_MASTER {
  1394  
  1395  			privilegedMembers[memberRole] = append(privilegedMembers[memberRole], member)
  1396  		}
  1397  	}
  1398  	return privilegedMembers
  1399  }
  1400  
  1401  func (o *Community) HasPermissionToSendCommunityEvents() bool {
  1402  	return !o.IsControlNode() && o.hasRoles(o.MemberIdentity(), manageCommunityRoles())
  1403  }
  1404  
  1405  func (o *Community) hasPermissionToSendCommunityEvent(event protobuf.CommunityEvent_EventType) bool {
  1406  	return !o.IsControlNode() && canRolesPerformEvent(o.rolesOf(o.MemberIdentity()), event)
  1407  }
  1408  
  1409  func (o *Community) hasPermissionToSendTokenPermissionCommunityEvent(event protobuf.CommunityEvent_EventType, permissionType protobuf.CommunityTokenPermission_Type) bool {
  1410  	roles := o.rolesOf(o.MemberIdentity())
  1411  	return !o.IsControlNode() && canRolesPerformEvent(roles, event) && canRolesModifyPermission(roles, permissionType)
  1412  }
  1413  
  1414  func (o *Community) IsMemberOwner(publicKey *ecdsa.PublicKey) bool {
  1415  	return o.hasRoles(publicKey, ownerRole())
  1416  }
  1417  
  1418  func (o *Community) IsMemberTokenMaster(publicKey *ecdsa.PublicKey) bool {
  1419  	return o.hasRoles(publicKey, tokenMasterRole())
  1420  }
  1421  
  1422  func (o *Community) IsMemberAdmin(publicKey *ecdsa.PublicKey) bool {
  1423  	return o.hasRoles(publicKey, adminRole())
  1424  }
  1425  
  1426  func (o *Community) IsPrivilegedMember(publicKey *ecdsa.PublicKey) bool {
  1427  	return o.hasRoles(publicKey, manageCommunityRoles())
  1428  }
  1429  
  1430  func manageCommunityRoles() map[protobuf.CommunityMember_Roles]bool {
  1431  	roles := make(map[protobuf.CommunityMember_Roles]bool)
  1432  	roles[protobuf.CommunityMember_ROLE_OWNER] = true
  1433  	roles[protobuf.CommunityMember_ROLE_ADMIN] = true
  1434  	roles[protobuf.CommunityMember_ROLE_TOKEN_MASTER] = true
  1435  	return roles
  1436  }
  1437  
  1438  func ownerRole() map[protobuf.CommunityMember_Roles]bool {
  1439  	roles := make(map[protobuf.CommunityMember_Roles]bool)
  1440  	roles[protobuf.CommunityMember_ROLE_OWNER] = true
  1441  	return roles
  1442  }
  1443  
  1444  func adminRole() map[protobuf.CommunityMember_Roles]bool {
  1445  	roles := make(map[protobuf.CommunityMember_Roles]bool)
  1446  	roles[protobuf.CommunityMember_ROLE_ADMIN] = true
  1447  	return roles
  1448  }
  1449  
  1450  func tokenMasterRole() map[protobuf.CommunityMember_Roles]bool {
  1451  	roles := make(map[protobuf.CommunityMember_Roles]bool)
  1452  	roles[protobuf.CommunityMember_ROLE_TOKEN_MASTER] = true
  1453  	return roles
  1454  }
  1455  
  1456  func (o *Community) MemberRole(pubKey *ecdsa.PublicKey) protobuf.CommunityMember_Roles {
  1457  	if o.IsMemberOwner(pubKey) {
  1458  		return protobuf.CommunityMember_ROLE_OWNER
  1459  	} else if o.IsMemberTokenMaster(pubKey) {
  1460  		return protobuf.CommunityMember_ROLE_TOKEN_MASTER
  1461  	} else if o.IsMemberAdmin(pubKey) {
  1462  		return protobuf.CommunityMember_ROLE_ADMIN
  1463  	}
  1464  
  1465  	return protobuf.CommunityMember_ROLE_NONE
  1466  }
  1467  
  1468  func (o *Community) validateRequestToJoinWithChatID(request *protobuf.CommunityRequestToJoin) error {
  1469  
  1470  	chat, ok := o.config.CommunityDescription.Chats[request.ChatId]
  1471  
  1472  	if !ok {
  1473  		return ErrChatNotFound
  1474  	}
  1475  
  1476  	// If chat is no permissions, access should not have been requested
  1477  	if chat.Permissions.Access != protobuf.CommunityPermissions_MANUAL_ACCEPT {
  1478  		return ErrCantRequestAccess
  1479  	}
  1480  
  1481  	if chat.Permissions.EnsOnly && len(request.EnsName) == 0 {
  1482  		return ErrCantRequestAccess
  1483  	}
  1484  
  1485  	return nil
  1486  }
  1487  
  1488  func (o *Community) ManualAccept() bool {
  1489  	return o.config.CommunityDescription.Permissions.Access == protobuf.CommunityPermissions_MANUAL_ACCEPT
  1490  }
  1491  
  1492  func (o *Community) AutoAccept() bool {
  1493  	// We no longer have the notion of "no membership", but for historical reasons
  1494  	// we use `NO_MEMBERSHIP` to determine wether requests to join should be automatically
  1495  	// accepted or not.
  1496  	return o.config.CommunityDescription.Permissions.Access == protobuf.CommunityPermissions_AUTO_ACCEPT
  1497  }
  1498  
  1499  func (o *Community) validateRequestToJoinWithoutChatID(request *protobuf.CommunityRequestToJoin) error {
  1500  	// Previously, requests to join a community where only necessary when the community
  1501  	// permissions were indeed set to `ON_REQUEST`.
  1502  	// Now, users always have to request access but can get accepted automatically
  1503  	// (if permissions are set to NO_MEMBERSHIP).
  1504  	//
  1505  	// Hence, not only do we check whether the community permissions are ON_REQUEST but
  1506  	// also NO_MEMBERSHIP.
  1507  	if o.config.CommunityDescription.Permissions.Access != protobuf.CommunityPermissions_MANUAL_ACCEPT && o.config.CommunityDescription.Permissions.Access != protobuf.CommunityPermissions_AUTO_ACCEPT {
  1508  		return ErrCantRequestAccess
  1509  	}
  1510  
  1511  	return nil
  1512  }
  1513  
  1514  func (o *Community) ID() types.HexBytes {
  1515  	return crypto.CompressPubkey(o.config.ID)
  1516  }
  1517  
  1518  func (o *Community) IDString() string {
  1519  	return types.EncodeHex(o.ID())
  1520  }
  1521  
  1522  func (o *Community) UncompressedIDString() string {
  1523  	return types.EncodeHex(crypto.FromECDSAPub(o.config.ID))
  1524  }
  1525  
  1526  func (o *Community) SerializedID() (string, error) {
  1527  	return multiformat.SerializeLegacyKey(o.UncompressedIDString())
  1528  }
  1529  
  1530  func (o *Community) StatusUpdatesChannelID() string {
  1531  	return o.IDString() + "-ping"
  1532  }
  1533  
  1534  func (o *Community) MagnetlinkMessageChannelID() string {
  1535  	return o.IDString() + "-magnetlinks"
  1536  }
  1537  
  1538  func (o *Community) MemberUpdateChannelID() string {
  1539  	return o.IDString() + "-memberUpdate"
  1540  }
  1541  
  1542  func (o *Community) PubsubTopic() string {
  1543  	return o.Shard().PubsubTopic()
  1544  }
  1545  
  1546  func (o *Community) PubsubTopicPrivateKey() *ecdsa.PrivateKey {
  1547  	return o.config.PubsubTopicPrivateKey
  1548  }
  1549  
  1550  func (o *Community) SetPubsubTopicPrivateKey(privKey *ecdsa.PrivateKey) {
  1551  	o.config.PubsubTopicPrivateKey = privKey
  1552  }
  1553  
  1554  func (o *Community) PubsubTopicKey() string {
  1555  	if o.config.PubsubTopicPrivateKey == nil {
  1556  		return ""
  1557  	}
  1558  	return hexutil.Encode(crypto.FromECDSAPub(&o.config.PubsubTopicPrivateKey.PublicKey))
  1559  }
  1560  
  1561  func (o *Community) PrivateKey() *ecdsa.PrivateKey {
  1562  	return o.config.PrivateKey
  1563  }
  1564  
  1565  func (o *Community) setPrivateKey(pk *ecdsa.PrivateKey) {
  1566  	if pk != nil {
  1567  		o.config.PrivateKey = pk
  1568  	}
  1569  }
  1570  
  1571  func (o *Community) SetResendAccountsClock(clock uint64) {
  1572  	o.config.CommunityDescription.ResendAccountsClock = clock
  1573  }
  1574  
  1575  func (o *Community) ControlNode() *ecdsa.PublicKey {
  1576  	if o.config.ControlNode == nil {
  1577  		return o.config.ID
  1578  	}
  1579  	return o.config.ControlNode
  1580  }
  1581  
  1582  func (o *Community) setControlNode(pubKey *ecdsa.PublicKey) {
  1583  	if pubKey != nil {
  1584  		o.config.ControlNode = pubKey
  1585  	}
  1586  }
  1587  
  1588  func (o *Community) PublicKey() *ecdsa.PublicKey {
  1589  	return o.config.ID
  1590  }
  1591  
  1592  func (o *Community) Description() *protobuf.CommunityDescription {
  1593  	return o.config.CommunityDescription
  1594  }
  1595  
  1596  func (o *Community) EncryptedDescription() (*protobuf.CommunityDescription, error) {
  1597  	clone := proto.Clone(o.config.CommunityDescription).(*protobuf.CommunityDescription)
  1598  	if o.encryptor != nil {
  1599  		err := encryptDescription(o.encryptor, o, clone)
  1600  		if err != nil {
  1601  			return nil, err
  1602  		}
  1603  	}
  1604  	return clone, nil
  1605  }
  1606  
  1607  func (o *Community) DescriptionProtocolMessage() []byte {
  1608  	return o.config.CommunityDescriptionProtocolMessage
  1609  }
  1610  
  1611  func (o *Community) marshaledDescription() ([]byte, error) {
  1612  	clone := proto.Clone(o.config.CommunityDescription).(*protobuf.CommunityDescription)
  1613  
  1614  	// This is only workaround to lower the size of the message that goes over the wire,
  1615  	// see https://github.com/status-im/status-desktop/issues/12188
  1616  	dehydrateChannelsMembers(clone)
  1617  
  1618  	err := generateBloomFiltersForChannels(clone, o.PrivateKey())
  1619  	if err != nil {
  1620  		o.config.Logger.Error("failed to generate bloom filters", zap.Error(err))
  1621  	}
  1622  
  1623  	if o.encryptor != nil {
  1624  		err := encryptDescription(o.encryptor, o, clone)
  1625  		if err != nil {
  1626  			return nil, err
  1627  		}
  1628  	}
  1629  
  1630  	return proto.Marshal(clone)
  1631  }
  1632  
  1633  func (o *Community) MarshaledDescription() ([]byte, error) {
  1634  	o.mutex.Lock()
  1635  	defer o.mutex.Unlock()
  1636  	return o.marshaledDescription()
  1637  }
  1638  
  1639  func (o *Community) toProtocolMessageBytes() ([]byte, error) {
  1640  	// If we are not a control node, use the received serialized version
  1641  	if !o.IsControlNode() {
  1642  		// This should not happen, as we can only serialize on our side if we
  1643  		// created the community
  1644  		if len(o.config.CommunityDescriptionProtocolMessage) == 0 {
  1645  			return nil, ErrNotControlNode
  1646  		}
  1647  
  1648  		return o.config.CommunityDescriptionProtocolMessage, nil
  1649  	}
  1650  
  1651  	// serialize
  1652  	payload, err := o.marshaledDescription()
  1653  	if err != nil {
  1654  		return nil, err
  1655  	}
  1656  
  1657  	// sign
  1658  	return protocol.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, o.config.PrivateKey)
  1659  }
  1660  
  1661  // ToProtocolMessageBytes returns the community in a wrapped & signed protocol message
  1662  func (o *Community) ToProtocolMessageBytes() ([]byte, error) {
  1663  	o.mutex.Lock()
  1664  	defer o.mutex.Unlock()
  1665  	return o.toProtocolMessageBytes()
  1666  }
  1667  
  1668  func dehydrateChannelsMembers(description *protobuf.CommunityDescription) {
  1669  	// To save space, we don't attach members for channels without permissions,
  1670  	// otherwise the message will hit waku msg size limit.
  1671  	for channelID, channel := range description.Chats {
  1672  		if !channelHasPermissions(ChatID(description.ID, channelID), description.TokenPermissions) {
  1673  			channel.Members = map[string]*protobuf.CommunityMember{} // clean members
  1674  		}
  1675  	}
  1676  }
  1677  
  1678  func hydrateChannelsMembers(description *protobuf.CommunityDescription) {
  1679  	for channelID, channel := range description.Chats {
  1680  		if !channelHasPermissions(ChatID(description.ID, channelID), description.TokenPermissions) {
  1681  			channel.Members = make(map[string]*protobuf.CommunityMember)
  1682  			for pubKey, member := range description.Members {
  1683  				channel.Members[pubKey] = member
  1684  			}
  1685  		}
  1686  	}
  1687  }
  1688  
  1689  func upgradeTokenPermissions(description *protobuf.CommunityDescription) {
  1690  
  1691  	floatToWeiIntFunc := func(floatStr string, decimals uint64) string {
  1692  		bigfloat := new(big.Float)
  1693  		bigfloat.SetString(floatStr)
  1694  
  1695  		multiplier := big.NewFloat(math.Pow(10, float64(decimals)))
  1696  		bigfloat.Mul(bigfloat, multiplier)
  1697  
  1698  		result := new(big.Int)
  1699  		bigfloat.Int(result)
  1700  		return result.String()
  1701  	}
  1702  
  1703  	for _, permission := range description.TokenPermissions {
  1704  		for _, criteria := range permission.TokenCriteria {
  1705  			if criteria.AmountInWei != "" {
  1706  				continue
  1707  			}
  1708  			// set AmountInWei if missing
  1709  			// Amount format (deprecated): "0.123"
  1710  			// AmountInWei format: "123000..000"
  1711  			if criteria.Type == protobuf.CommunityTokenType_ERC20 {
  1712  				criteria.AmountInWei = floatToWeiIntFunc(criteria.Amount, criteria.Decimals)
  1713  			} else {
  1714  				criteria.AmountInWei = criteria.Amount
  1715  			}
  1716  		}
  1717  	}
  1718  }
  1719  
  1720  func (o *Community) Chats() map[string]*protobuf.CommunityChat {
  1721  	// Why are we checking here for nil, it should be the responsibility of the caller
  1722  	if o == nil {
  1723  		return make(map[string]*protobuf.CommunityChat)
  1724  	}
  1725  
  1726  	o.mutex.Lock()
  1727  	defer o.mutex.Unlock()
  1728  
  1729  	return o.chats()
  1730  }
  1731  
  1732  func (o *Community) chats() map[string]*protobuf.CommunityChat {
  1733  	response := make(map[string]*protobuf.CommunityChat)
  1734  
  1735  	if o.config != nil && o.config.CommunityDescription != nil {
  1736  		for k, v := range o.config.CommunityDescription.Chats {
  1737  			response[k] = v
  1738  		}
  1739  	}
  1740  
  1741  	return response
  1742  }
  1743  
  1744  func (o *Community) Images() map[string]*protobuf.IdentityImage {
  1745  	response := make(map[string]*protobuf.IdentityImage)
  1746  
  1747  	// Why are we checking here for nil, it should be the responsibility of the caller
  1748  	if o == nil {
  1749  		return response
  1750  	}
  1751  
  1752  	o.mutex.Lock()
  1753  	defer o.mutex.Unlock()
  1754  
  1755  	if o.config != nil && o.config.CommunityDescription != nil && o.config.CommunityDescription.Identity != nil {
  1756  		for k, v := range o.config.CommunityDescription.Identity.Images {
  1757  			response[k] = v
  1758  		}
  1759  	}
  1760  
  1761  	return response
  1762  }
  1763  
  1764  func (o *Community) Categories() map[string]*protobuf.CommunityCategory {
  1765  	response := make(map[string]*protobuf.CommunityCategory)
  1766  
  1767  	if o == nil {
  1768  		return response
  1769  	}
  1770  
  1771  	o.mutex.Lock()
  1772  	defer o.mutex.Unlock()
  1773  
  1774  	if o.config != nil && o.config.CommunityDescription != nil {
  1775  		for k, v := range o.config.CommunityDescription.Categories {
  1776  			response[k] = v
  1777  		}
  1778  	}
  1779  
  1780  	return response
  1781  }
  1782  
  1783  func (o *Community) tokenPermissions() map[string]*CommunityTokenPermission {
  1784  	result := make(map[string]*CommunityTokenPermission, len(o.config.CommunityDescription.TokenPermissions))
  1785  	for _, tokenPermission := range o.config.CommunityDescription.TokenPermissions {
  1786  		result[tokenPermission.Id] = NewCommunityTokenPermission(tokenPermission)
  1787  	}
  1788  
  1789  	// Non-privileged members should not see pending permissions
  1790  	if o.config.EventsData == nil || !o.IsPrivilegedMember(o.MemberIdentity()) {
  1791  		return result
  1792  	}
  1793  
  1794  	processedPermissions := make(map[string]*struct{})
  1795  	for _, event := range o.config.EventsData.Events {
  1796  		if event.TokenPermission == nil || processedPermissions[event.TokenPermission.Id] != nil {
  1797  			continue
  1798  		}
  1799  		processedPermissions[event.TokenPermission.Id] = &struct{}{} // first permission event wins
  1800  
  1801  		switch event.Type {
  1802  		case protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE:
  1803  			eventsTokenPermission := NewCommunityTokenPermission(event.TokenPermission)
  1804  			if result[event.TokenPermission.Id] != nil {
  1805  				eventsTokenPermission.State = TokenPermissionUpdatePending
  1806  			} else {
  1807  				eventsTokenPermission.State = TokenPermissionAdditionPending
  1808  			}
  1809  			result[eventsTokenPermission.Id] = eventsTokenPermission
  1810  
  1811  		case protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE:
  1812  			tokenPermission := result[event.TokenPermission.Id]
  1813  			if tokenPermission != nil {
  1814  				tokenPermission.State = TokenPermissionRemovalPending
  1815  			}
  1816  		default:
  1817  		}
  1818  	}
  1819  
  1820  	return result
  1821  }
  1822  
  1823  func (o *Community) PendingAndBannedMembers() map[string]CommunityMemberState {
  1824  	result := make(map[string]CommunityMemberState)
  1825  
  1826  	if o.config.CommunityDescription.BannedMembers != nil {
  1827  		for bannedMemberID, banInfo := range o.config.CommunityDescription.BannedMembers {
  1828  			state := CommunityMemberBanned
  1829  			if banInfo.DeleteAllMessages {
  1830  				state = CommunityMemberBanWithAllMessagesDelete
  1831  			}
  1832  			result[bannedMemberID] = state
  1833  		}
  1834  	}
  1835  
  1836  	for _, bannedMemberID := range o.config.CommunityDescription.BanList {
  1837  		if _, exists := result[bannedMemberID]; !exists {
  1838  			result[bannedMemberID] = CommunityMemberBanned
  1839  		}
  1840  	}
  1841  
  1842  	if o.config.EventsData == nil {
  1843  		return result
  1844  	}
  1845  
  1846  	processedEvents := make(map[string]bool)
  1847  	for _, event := range o.config.EventsData.Events {
  1848  		if processedEvents[event.MemberToAction] {
  1849  			continue
  1850  		}
  1851  
  1852  		switch event.Type {
  1853  		case protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK:
  1854  			result[event.MemberToAction] = CommunityMemberKickPending
  1855  		case protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN:
  1856  			result[event.MemberToAction] = CommunityMemberBanPending
  1857  		case protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN:
  1858  			result[event.MemberToAction] = CommunityMemberUnbanPending
  1859  		default:
  1860  			continue
  1861  		}
  1862  		processedEvents[event.MemberToAction] = true
  1863  	}
  1864  
  1865  	return result
  1866  }
  1867  
  1868  func (o *Community) TokenPermissions() map[string]*CommunityTokenPermission {
  1869  	o.mutex.Lock()
  1870  	defer o.mutex.Unlock()
  1871  	return o.tokenPermissions()
  1872  }
  1873  
  1874  func (o *Community) HasTokenPermissions() bool {
  1875  	o.mutex.Lock()
  1876  	defer o.mutex.Unlock()
  1877  	return len(o.tokenPermissions()) > 0
  1878  }
  1879  
  1880  func channelHasPermissions(chatID string, permissions map[string]*protobuf.CommunityTokenPermission) bool {
  1881  	for _, p := range permissions {
  1882  		if includes(p.ChatIds, chatID) {
  1883  			return true
  1884  		}
  1885  	}
  1886  
  1887  	return false
  1888  }
  1889  
  1890  func channelEncrypted(chatID string, permissions map[string]*protobuf.CommunityTokenPermission) bool {
  1891  	hasPermission := false
  1892  	viewableByEveryone := false
  1893  
  1894  	for _, p := range permissions {
  1895  		if !includes(p.ChatIds, chatID) {
  1896  			continue
  1897  		}
  1898  
  1899  		hasPermission = true
  1900  
  1901  		if p.Type == protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL &&
  1902  			len(p.TokenCriteria) == 0 {
  1903  			viewableByEveryone = true
  1904  			break
  1905  		}
  1906  	}
  1907  
  1908  	return hasPermission && !viewableByEveryone
  1909  }
  1910  
  1911  func (o *Community) channelEncrypted(channelID string) bool {
  1912  	return channelEncrypted(o.ChatID(channelID), o.config.CommunityDescription.TokenPermissions)
  1913  }
  1914  
  1915  func (o *Community) ChannelEncrypted(channelID string) bool {
  1916  	o.mutex.Lock()
  1917  	defer o.mutex.Unlock()
  1918  	return o.channelEncrypted(channelID)
  1919  }
  1920  
  1921  func (o *Community) HasMissingEncryptionKey(channelID string) bool {
  1922  	o.mutex.Lock()
  1923  	defer o.mutex.Unlock()
  1924  
  1925  	return o.channelEncrypted(channelID) &&
  1926  		!o.isMemberInChat(o.MemberIdentity(), channelID) &&
  1927  		o.IsMemberLikelyInChat(channelID)
  1928  }
  1929  
  1930  func TokenPermissionsByType(permissions map[string]*CommunityTokenPermission, permissionType protobuf.CommunityTokenPermission_Type) []*CommunityTokenPermission {
  1931  	result := make([]*CommunityTokenPermission, 0)
  1932  	for _, tokenPermission := range permissions {
  1933  		if tokenPermission.Type == permissionType {
  1934  			result = append(result, tokenPermission)
  1935  		}
  1936  	}
  1937  	return result
  1938  }
  1939  
  1940  func (o *Community) tokenPermissionByID(ID string) *CommunityTokenPermission {
  1941  	return o.tokenPermissions()[ID]
  1942  }
  1943  
  1944  func (o *Community) TokenPermissionByID(ID string) *CommunityTokenPermission {
  1945  	o.mutex.Lock()
  1946  	defer o.mutex.Unlock()
  1947  
  1948  	return o.tokenPermissionByID(ID)
  1949  }
  1950  
  1951  func (o *Community) TokenPermissionsByType(permissionType protobuf.CommunityTokenPermission_Type) []*CommunityTokenPermission {
  1952  	return TokenPermissionsByType(o.tokenPermissions(), permissionType)
  1953  }
  1954  
  1955  func (o *Community) ChannelTokenPermissionsByType(channelID string, permissionType protobuf.CommunityTokenPermission_Type) []*CommunityTokenPermission {
  1956  	permissions := make([]*CommunityTokenPermission, 0)
  1957  	for _, tokenPermission := range o.tokenPermissions() {
  1958  		if tokenPermission.Type == permissionType && includes(tokenPermission.ChatIds, channelID) {
  1959  			permissions = append(permissions, tokenPermission)
  1960  		}
  1961  	}
  1962  	return permissions
  1963  }
  1964  
  1965  func includes(channelIDs []string, channelID string) bool {
  1966  	for _, id := range channelIDs {
  1967  		if id == channelID {
  1968  			return true
  1969  		}
  1970  	}
  1971  	return false
  1972  }
  1973  
  1974  func (o *Community) UpsertTokenPermission(tokenPermission *protobuf.CommunityTokenPermission) (*CommunityChanges, error) {
  1975  	o.mutex.Lock()
  1976  	defer o.mutex.Unlock()
  1977  
  1978  	if o.IsControlNode() {
  1979  		changes, err := o.upsertTokenPermission(tokenPermission)
  1980  		if err != nil {
  1981  			return nil, err
  1982  		}
  1983  
  1984  		o.increaseClock()
  1985  
  1986  		return changes, nil
  1987  	}
  1988  
  1989  	if o.hasPermissionToSendTokenPermissionCommunityEvent(protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE, tokenPermission.Type) {
  1990  		existed := o.tokenPermissionByID(tokenPermission.Id) != nil
  1991  
  1992  		err := o.addNewCommunityEvent(o.ToCommunityTokenPermissionChangeCommunityEvent(tokenPermission))
  1993  		if err != nil {
  1994  			return nil, err
  1995  		}
  1996  
  1997  		permission := NewCommunityTokenPermission(tokenPermission)
  1998  
  1999  		changes := o.emptyCommunityChanges()
  2000  		if existed {
  2001  			permission.State = TokenPermissionUpdatePending
  2002  			changes.TokenPermissionsModified[tokenPermission.Id] = permission
  2003  		} else {
  2004  			permission.State = TokenPermissionAdditionPending
  2005  			changes.TokenPermissionsAdded[tokenPermission.Id] = permission
  2006  		}
  2007  
  2008  		return changes, nil
  2009  	}
  2010  
  2011  	return nil, ErrNotAuthorized
  2012  }
  2013  
  2014  func (o *Community) DeleteTokenPermission(permissionID string) (*CommunityChanges, error) {
  2015  	o.mutex.Lock()
  2016  	defer o.mutex.Unlock()
  2017  
  2018  	tokenPermission, exists := o.config.CommunityDescription.TokenPermissions[permissionID]
  2019  	if !exists {
  2020  		return nil, ErrTokenPermissionNotFound
  2021  	}
  2022  
  2023  	if o.IsControlNode() {
  2024  		changes, err := o.deleteTokenPermission(permissionID)
  2025  		if err != nil {
  2026  			return nil, err
  2027  		}
  2028  
  2029  		o.increaseClock()
  2030  
  2031  		return changes, nil
  2032  	}
  2033  
  2034  	if o.hasPermissionToSendTokenPermissionCommunityEvent(protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE, tokenPermission.Type) {
  2035  		err := o.addNewCommunityEvent(o.ToCommunityTokenPermissionDeleteCommunityEvent(tokenPermission))
  2036  		if err != nil {
  2037  			return nil, err
  2038  		}
  2039  
  2040  		permission := NewCommunityTokenPermission(tokenPermission)
  2041  		permission.State = TokenPermissionRemovalPending
  2042  
  2043  		changes := o.emptyCommunityChanges()
  2044  		changes.TokenPermissionsModified[permission.Id] = permission
  2045  
  2046  		return changes, nil
  2047  	}
  2048  
  2049  	return nil, ErrNotAuthorized
  2050  }
  2051  
  2052  func (o *Community) VerifyGrantSignature(data []byte) (*protobuf.Grant, error) {
  2053  	if len(data) <= signatureLength {
  2054  		return nil, ErrInvalidGrant
  2055  	}
  2056  	signature := data[:signatureLength]
  2057  	payload := data[signatureLength:]
  2058  	grant := &protobuf.Grant{}
  2059  	err := proto.Unmarshal(payload, grant)
  2060  	if err != nil {
  2061  		return nil, err
  2062  	}
  2063  
  2064  	if grant.Clock == 0 {
  2065  		return nil, ErrInvalidGrant
  2066  	}
  2067  	if grant.MemberId == nil {
  2068  		return nil, ErrInvalidGrant
  2069  	}
  2070  	if !bytes.Equal(grant.CommunityId, o.ID()) {
  2071  		return nil, ErrInvalidGrant
  2072  	}
  2073  	if grant.Expires < uint64(time.Now().UnixMilli()) {
  2074  		return nil, ErrGrantExpired
  2075  	}
  2076  
  2077  	extractedPublicKey, err := crypto.SigToPub(crypto.Keccak256(payload), signature)
  2078  	if err != nil {
  2079  		return nil, err
  2080  	}
  2081  
  2082  	if !common.IsPubKeyEqual(o.ControlNode(), extractedPublicKey) {
  2083  		return nil, ErrInvalidGrant
  2084  	}
  2085  
  2086  	return grant, nil
  2087  }
  2088  
  2089  func (o *Community) CanView(pk *ecdsa.PublicKey, chatID string) bool {
  2090  	if o.config.CommunityDescription.Chats == nil {
  2091  		o.config.Logger.Debug("Community.CanView: no-chats")
  2092  		return false
  2093  	}
  2094  
  2095  	chat, ok := o.config.CommunityDescription.Chats[chatID]
  2096  	if !ok {
  2097  		o.config.Logger.Debug("Community.CanView: no chat with id", zap.String("chat-id", chatID))
  2098  		return false
  2099  	}
  2100  
  2101  	// community creator can always post, return immediately
  2102  	if common.IsPubKeyEqual(pk, o.ControlNode()) {
  2103  		return true
  2104  	}
  2105  
  2106  	if o.isBanned(pk) {
  2107  		o.config.Logger.Debug("Community.CanView: user is banned", zap.String("chat-id", chatID))
  2108  		return false
  2109  	}
  2110  
  2111  	if o.config.CommunityDescription.Members == nil {
  2112  		o.config.Logger.Debug("Community.CanView: no members in org", zap.String("chat-id", chatID))
  2113  		return false
  2114  	}
  2115  
  2116  	// If community member, also check chat membership next
  2117  	_, ok = o.config.CommunityDescription.Members[common.PubkeyToHex(pk)]
  2118  	if !ok {
  2119  		o.config.Logger.Debug("Community.CanView: not a community member", zap.String("chat-id", chatID))
  2120  		return false
  2121  	}
  2122  
  2123  	if chat.Members == nil {
  2124  		o.config.Logger.Debug("Community.CanView: no members in chat", zap.String("chat-id", chatID))
  2125  		return false
  2126  	}
  2127  
  2128  	_, isChatMember := chat.Members[common.PubkeyToHex(pk)]
  2129  	return isChatMember
  2130  }
  2131  
  2132  func (o *Community) CanPost(pk *ecdsa.PublicKey, chatID string, messageType protobuf.ApplicationMetadataMessage_Type) (bool, error) {
  2133  	hasAccessToChat := o.CanView(pk, chatID)
  2134  	if !hasAccessToChat {
  2135  		return false, nil
  2136  	}
  2137  
  2138  	chat := o.config.CommunityDescription.Chats[chatID]
  2139  	member := chat.Members[common.PubkeyToHex(pk)]
  2140  
  2141  	switch messageType {
  2142  	case protobuf.ApplicationMetadataMessage_PIN_MESSAGE:
  2143  		pinAllowed := o.IsPrivilegedMember(pk) || o.AllowsAllMembersToPinMessage()
  2144  		return pinAllowed, nil
  2145  
  2146  	case protobuf.ApplicationMetadataMessage_EMOJI_REACTION:
  2147  		isPoster := member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_POSTER
  2148  		isViewer := member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_VIEWER
  2149  		return isPoster || (isViewer && chat.ViewersCanPostReactions), nil
  2150  
  2151  	default:
  2152  		return member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_POSTER, nil
  2153  	}
  2154  }
  2155  
  2156  func (o *Community) BuildGrant(key *ecdsa.PublicKey, chatID string) ([]byte, error) {
  2157  	return o.buildGrant(key, chatID)
  2158  }
  2159  
  2160  func (o *Community) buildGrant(key *ecdsa.PublicKey, chatID string) ([]byte, error) {
  2161  	bytes := make([]byte, 0)
  2162  	if o.IsControlNode() {
  2163  		grant := &protobuf.Grant{
  2164  			CommunityId: o.ID(),
  2165  			MemberId:    crypto.CompressPubkey(key),
  2166  			ChatId:      chatID,
  2167  			Clock:       o.config.CommunityDescription.Clock,
  2168  			Expires:     uint64(time.Now().Add(GrantExpirationTime).UnixMilli()),
  2169  		}
  2170  		marshaledGrant, err := proto.Marshal(grant)
  2171  		if err != nil {
  2172  			return nil, err
  2173  		}
  2174  
  2175  		signatureMaterial := crypto.Keccak256(marshaledGrant)
  2176  
  2177  		signature, err := crypto.Sign(signatureMaterial, o.config.PrivateKey)
  2178  		if err != nil {
  2179  			return nil, err
  2180  		}
  2181  
  2182  		bytes = append(signature, marshaledGrant...)
  2183  	}
  2184  	return bytes, nil
  2185  }
  2186  
  2187  func (o *Community) increaseClock() {
  2188  	o.config.CommunityDescription.Clock = o.nextClock()
  2189  }
  2190  
  2191  func (o *Community) Clock() uint64 {
  2192  	return o.config.CommunityDescription.Clock
  2193  }
  2194  
  2195  func (o *Community) CanRequestAccess(pk *ecdsa.PublicKey) bool {
  2196  	if o.hasMember(pk) {
  2197  		return false
  2198  	}
  2199  
  2200  	if o.config.CommunityDescription == nil {
  2201  		return false
  2202  	}
  2203  
  2204  	if o.config.CommunityDescription.Permissions == nil {
  2205  		return false
  2206  	}
  2207  
  2208  	return o.config.CommunityDescription.Permissions.Access == protobuf.CommunityPermissions_MANUAL_ACCEPT
  2209  }
  2210  
  2211  func (o *Community) CanManageUsers(pk *ecdsa.PublicKey) bool {
  2212  	o.mutex.Lock()
  2213  	defer o.mutex.Unlock()
  2214  
  2215  	return o.IsPrivilegedMember(pk)
  2216  }
  2217  
  2218  func (o *Community) CanDeleteMessageForEveryone(pk *ecdsa.PublicKey) bool {
  2219  	o.mutex.Lock()
  2220  	defer o.mutex.Unlock()
  2221  
  2222  	return o.IsPrivilegedMember(pk)
  2223  }
  2224  
  2225  func (o *Community) isMember() bool {
  2226  	return o.hasMember(o.MemberIdentity())
  2227  }
  2228  
  2229  func (o *Community) CanMemberIdentityPost(chatID string, messageType protobuf.ApplicationMetadataMessage_Type) (bool, error) {
  2230  	return o.CanPost(o.MemberIdentity(), chatID, messageType)
  2231  }
  2232  
  2233  // CanJoin returns whether a user can join the community, only if it's
  2234  func (o *Community) canJoin() bool {
  2235  	if o.config.Joined {
  2236  		return false
  2237  	}
  2238  
  2239  	if o.IsControlNode() {
  2240  		return true
  2241  	}
  2242  
  2243  	if o.config.CommunityDescription.Permissions.Access == protobuf.CommunityPermissions_AUTO_ACCEPT {
  2244  		return true
  2245  	}
  2246  
  2247  	return o.isMember()
  2248  }
  2249  
  2250  func (o *Community) RequestedToJoinAt() uint64 {
  2251  	return o.config.RequestedToJoinAt
  2252  }
  2253  
  2254  func (o *Community) nextClock() uint64 {
  2255  	// lamport timestamp
  2256  	clock := o.config.CommunityDescription.Clock
  2257  	timestamp := o.timesource.GetCurrentTime()
  2258  	if clock == 0 || clock < timestamp {
  2259  		clock = timestamp
  2260  	} else {
  2261  		clock = clock + 1
  2262  	}
  2263  
  2264  	return clock
  2265  }
  2266  
  2267  func (o *Community) CanManageUsersPublicKeys() ([]*ecdsa.PublicKey, error) {
  2268  	var response []*ecdsa.PublicKey
  2269  	roles := manageCommunityRoles()
  2270  	for pkString, member := range o.config.CommunityDescription.Members {
  2271  		if o.memberHasRoles(member, roles) {
  2272  			pk, err := common.HexToPubkey(pkString)
  2273  			if err != nil {
  2274  				return nil, err
  2275  			}
  2276  
  2277  			response = append(response, pk)
  2278  		}
  2279  
  2280  	}
  2281  	return response, nil
  2282  }
  2283  
  2284  func (o *Community) AddRequestToJoin(request *RequestToJoin) {
  2285  	o.config.RequestsToJoin = append(o.config.RequestsToJoin, request)
  2286  }
  2287  
  2288  func (o *Community) RequestsToJoin() []*RequestToJoin {
  2289  	return o.config.RequestsToJoin
  2290  }
  2291  
  2292  func (o *Community) AddMember(publicKey *ecdsa.PublicKey, roles []protobuf.CommunityMember_Roles, lastUpdateClock uint64) (*CommunityChanges, error) {
  2293  	if !o.IsControlNode() {
  2294  		return nil, ErrNotControlNode
  2295  	}
  2296  
  2297  	memberKey := common.PubkeyToHex(publicKey)
  2298  	changes := o.emptyCommunityChanges()
  2299  
  2300  	if o.config.CommunityDescription.Members == nil {
  2301  		o.config.CommunityDescription.Members = make(map[string]*protobuf.CommunityMember)
  2302  	}
  2303  
  2304  	if _, ok := o.config.CommunityDescription.Members[memberKey]; !ok {
  2305  		o.config.CommunityDescription.Members[memberKey] = &protobuf.CommunityMember{Roles: roles, LastUpdateClock: lastUpdateClock}
  2306  		changes.MembersAdded[memberKey] = o.config.CommunityDescription.Members[memberKey]
  2307  	}
  2308  
  2309  	o.increaseClock()
  2310  
  2311  	return changes, nil
  2312  }
  2313  
  2314  func (o *Community) AddMemberToChat(chatID string, publicKey *ecdsa.PublicKey,
  2315  	roles []protobuf.CommunityMember_Roles, channelRole protobuf.CommunityMember_ChannelRole) (*CommunityChanges, error) {
  2316  
  2317  	o.mutex.Lock()
  2318  	defer o.mutex.Unlock()
  2319  
  2320  	if !o.IsControlNode() {
  2321  		return nil, ErrNotControlNode
  2322  	}
  2323  
  2324  	memberKey := common.PubkeyToHex(publicKey)
  2325  	changes := o.emptyCommunityChanges()
  2326  
  2327  	chat, ok := o.config.CommunityDescription.Chats[chatID]
  2328  	if !ok {
  2329  		return nil, ErrChatNotFound
  2330  	}
  2331  
  2332  	if chat.Members == nil {
  2333  		chat.Members = make(map[string]*protobuf.CommunityMember)
  2334  	}
  2335  	chat.Members[memberKey] = &protobuf.CommunityMember{
  2336  		Roles:       roles,
  2337  		ChannelRole: channelRole,
  2338  	}
  2339  	changes.ChatsModified[chatID] = &CommunityChatChanges{
  2340  		ChatModified: chat,
  2341  		MembersAdded: map[string]*protobuf.CommunityMember{
  2342  			memberKey: chat.Members[memberKey],
  2343  		},
  2344  	}
  2345  
  2346  	if o.IsControlNode() {
  2347  		o.increaseClock()
  2348  	}
  2349  
  2350  	return changes, nil
  2351  }
  2352  
  2353  func (o *Community) PopulateChannelsWithAllMembers() {
  2354  	members := o.Members()
  2355  	for _, channel := range o.Chats() {
  2356  		channel.Members = members
  2357  	}
  2358  	o.increaseClock()
  2359  }
  2360  
  2361  func (o *Community) PopulateChatWithAllMembers(chatID string) (*CommunityChanges, error) {
  2362  	o.mutex.Lock()
  2363  	defer o.mutex.Unlock()
  2364  
  2365  	if !o.IsControlNode() {
  2366  		return o.emptyCommunityChanges(), ErrNotControlNode
  2367  	}
  2368  
  2369  	return o.populateChatWithAllMembers(chatID)
  2370  }
  2371  
  2372  func (o *Community) populateChatWithAllMembers(chatID string) (*CommunityChanges, error) {
  2373  	result := o.emptyCommunityChanges()
  2374  
  2375  	chat, exists := o.chats()[chatID]
  2376  	if !exists {
  2377  		return result, ErrChatNotFound
  2378  	}
  2379  
  2380  	membersAdded := make(map[string]*protobuf.CommunityMember)
  2381  	for pubKey, member := range o.Members() {
  2382  		if chat.Members[pubKey] == nil {
  2383  			membersAdded[pubKey] = member
  2384  		}
  2385  	}
  2386  	result.ChatsModified[chatID] = &CommunityChatChanges{
  2387  		MembersAdded: membersAdded,
  2388  	}
  2389  
  2390  	chat.Members = o.Members()
  2391  	o.increaseClock()
  2392  
  2393  	return result, nil
  2394  }
  2395  
  2396  func ChatID(communityID, channelID string) string {
  2397  	return communityID + channelID
  2398  }
  2399  
  2400  func (o *Community) ChatID(channelID string) string {
  2401  	return ChatID(o.IDString(), channelID)
  2402  }
  2403  
  2404  func (o *Community) ChatIDs() (chatIDs []string) {
  2405  	for channelID := range o.config.CommunityDescription.Chats {
  2406  		chatIDs = append(chatIDs, o.ChatID(channelID))
  2407  	}
  2408  	return chatIDs
  2409  }
  2410  
  2411  func (o *Community) AllowsAllMembersToPinMessage() bool {
  2412  	return o.config.CommunityDescription.AdminSettings != nil && o.config.CommunityDescription.AdminSettings.PinMessageAllMembersEnabled
  2413  }
  2414  
  2415  func (o *Community) CreateDeepCopy() *Community {
  2416  	return &Community{
  2417  		encryptor: o.encryptor,
  2418  		config: &Config{
  2419  			PrivateKey:                          o.config.PrivateKey,
  2420  			ControlNode:                         o.config.ControlNode,
  2421  			ControlDevice:                       o.config.ControlDevice,
  2422  			CommunityDescription:                proto.Clone(o.config.CommunityDescription).(*protobuf.CommunityDescription),
  2423  			CommunityDescriptionProtocolMessage: o.config.CommunityDescriptionProtocolMessage,
  2424  			ID:                                  o.config.ID,
  2425  			Joined:                              o.config.Joined,
  2426  			JoinedAt:                            o.config.JoinedAt,
  2427  			Requested:                           o.config.Requested,
  2428  			Verified:                            o.config.Verified,
  2429  			Spectated:                           o.config.Spectated,
  2430  			Muted:                               o.config.Muted,
  2431  			MuteTill:                            o.config.MuteTill,
  2432  			Logger:                              o.config.Logger,
  2433  			RequestedToJoinAt:                   o.config.RequestedToJoinAt,
  2434  			RequestsToJoin:                      o.config.RequestsToJoin,
  2435  			MemberIdentity:                      o.config.MemberIdentity,
  2436  			EventsData:                          o.config.EventsData,
  2437  			Shard:                               o.config.Shard,
  2438  			PubsubTopicPrivateKey:               o.config.PubsubTopicPrivateKey,
  2439  			LastOpenedAt:                        o.config.LastOpenedAt,
  2440  		},
  2441  		timesource: o.timesource,
  2442  	}
  2443  }
  2444  
  2445  func (o *Community) SetActiveMembersCount(activeMembersCount uint64) (updated bool, err error) {
  2446  	o.mutex.Lock()
  2447  	defer o.mutex.Unlock()
  2448  
  2449  	if !o.IsControlNode() {
  2450  		return false, ErrNotControlNode
  2451  	}
  2452  
  2453  	if activeMembersCount == o.config.CommunityDescription.ActiveMembersCount {
  2454  		return false, nil
  2455  	}
  2456  
  2457  	o.config.CommunityDescription.ActiveMembersCount = activeMembersCount
  2458  	o.increaseClock()
  2459  
  2460  	return true, nil
  2461  }
  2462  
  2463  type sortSlice []sorterHelperIdx
  2464  type sorterHelperIdx struct {
  2465  	pos    int32
  2466  	catID  string
  2467  	chatID string
  2468  }
  2469  
  2470  func (d sortSlice) Len() int {
  2471  	return len(d)
  2472  }
  2473  
  2474  func (d sortSlice) Swap(i, j int) {
  2475  	d[i], d[j] = d[j], d[i]
  2476  }
  2477  
  2478  func (d sortSlice) Less(i, j int) bool {
  2479  	return d[i].pos < d[j].pos
  2480  }
  2481  
  2482  func (o *Community) unbanUserFromCommunity(pk *ecdsa.PublicKey) {
  2483  	key := common.PubkeyToHex(pk)
  2484  	for i, v := range o.config.CommunityDescription.BanList {
  2485  		if v == key {
  2486  			o.config.CommunityDescription.BanList =
  2487  				append(o.config.CommunityDescription.BanList[:i], o.config.CommunityDescription.BanList[i+1:]...)
  2488  			break
  2489  		}
  2490  	}
  2491  
  2492  	if o.config.CommunityDescription.BannedMembers != nil {
  2493  		delete(o.config.CommunityDescription.BannedMembers, key)
  2494  	}
  2495  }
  2496  
  2497  func (o *Community) banUserFromCommunity(pk *ecdsa.PublicKey, communityBanInfo *protobuf.CommunityBanInfo) {
  2498  	key := common.PubkeyToHex(pk)
  2499  	if o.hasMember(pk) {
  2500  		// Remove from org
  2501  		delete(o.config.CommunityDescription.Members, key)
  2502  
  2503  		// Remove from chats
  2504  		for _, chat := range o.config.CommunityDescription.Chats {
  2505  			delete(chat.Members, key)
  2506  		}
  2507  	}
  2508  
  2509  	if o.config.CommunityDescription.BannedMembers == nil {
  2510  		o.config.CommunityDescription.BannedMembers = make(map[string]*protobuf.CommunityBanInfo)
  2511  	}
  2512  
  2513  	if _, exists := o.config.CommunityDescription.BannedMembers[key]; !exists {
  2514  		o.config.CommunityDescription.BannedMembers[key] = communityBanInfo
  2515  	}
  2516  
  2517  	for _, u := range o.config.CommunityDescription.BanList {
  2518  		if u == key {
  2519  			return
  2520  		}
  2521  	}
  2522  
  2523  	o.config.CommunityDescription.BanList = append(o.config.CommunityDescription.BanList, key)
  2524  }
  2525  
  2526  func (o *Community) deleteBannedMemberAllMessages(pk *ecdsa.PublicKey) error {
  2527  	key := common.PubkeyToHex(pk)
  2528  
  2529  	if o.config.CommunityDescription.BannedMembers == nil {
  2530  		return ErrBannedMemberNotFound
  2531  	}
  2532  
  2533  	if _, exists := o.config.CommunityDescription.BannedMembers[key]; !exists {
  2534  		return ErrBannedMemberNotFound
  2535  	}
  2536  
  2537  	o.config.CommunityDescription.BannedMembers[key].DeleteAllMessages = true
  2538  	return nil
  2539  }
  2540  
  2541  func (o *Community) editChat(chatID string, chat *protobuf.CommunityChat) error {
  2542  	err := validateCommunityChat(o.config.CommunityDescription, chat)
  2543  	if err != nil {
  2544  		return err
  2545  	}
  2546  
  2547  	if o.config.CommunityDescription.Chats == nil {
  2548  		o.config.CommunityDescription.Chats = make(map[string]*protobuf.CommunityChat)
  2549  	}
  2550  	if _, exists := o.config.CommunityDescription.Chats[chatID]; !exists {
  2551  		return ErrChatNotFound
  2552  	}
  2553  
  2554  	o.config.CommunityDescription.Chats[chatID] = chat
  2555  
  2556  	return nil
  2557  }
  2558  
  2559  func (o *Community) createChat(chatID string, chat *protobuf.CommunityChat) error {
  2560  	err := validateCommunityChat(o.config.CommunityDescription, chat)
  2561  	if err != nil {
  2562  		return err
  2563  	}
  2564  
  2565  	if o.config.CommunityDescription.Chats == nil {
  2566  		o.config.CommunityDescription.Chats = make(map[string]*protobuf.CommunityChat)
  2567  	}
  2568  	if _, ok := o.config.CommunityDescription.Chats[chatID]; ok {
  2569  		return ErrChatAlreadyExists
  2570  	}
  2571  
  2572  	for _, c := range o.config.CommunityDescription.Chats {
  2573  		if chat.Identity.DisplayName == c.Identity.DisplayName {
  2574  			return ErrInvalidCommunityDescriptionDuplicatedName
  2575  		}
  2576  	}
  2577  
  2578  	// Sets the chat position to be the last within its category
  2579  	chat.Position = 0
  2580  	for _, c := range o.config.CommunityDescription.Chats {
  2581  		if c.CategoryId == chat.CategoryId {
  2582  			chat.Position++
  2583  		}
  2584  	}
  2585  
  2586  	chat.Members = make(map[string]*protobuf.CommunityMember)
  2587  	for pubKey, member := range o.config.CommunityDescription.Members {
  2588  		chat.Members[pubKey] = member
  2589  	}
  2590  
  2591  	o.config.CommunityDescription.Chats[chatID] = chat
  2592  
  2593  	return nil
  2594  }
  2595  
  2596  func (o *Community) deleteChat(chatID string) *CommunityChanges {
  2597  	if o.config.CommunityDescription.Chats == nil {
  2598  		o.config.CommunityDescription.Chats = make(map[string]*protobuf.CommunityChat)
  2599  	}
  2600  
  2601  	changes := o.emptyCommunityChanges()
  2602  
  2603  	if chat, exists := o.config.CommunityDescription.Chats[chatID]; exists {
  2604  		tmpCatID := chat.CategoryId
  2605  		chat.CategoryId = ""
  2606  		o.SortCategoryChats(changes, tmpCatID)
  2607  		changes.ChatsRemoved[chatID] = chat
  2608  	}
  2609  
  2610  	delete(o.config.CommunityDescription.Chats, chatID)
  2611  	return changes
  2612  }
  2613  
  2614  func (o *Community) upsertTokenPermission(permission *protobuf.CommunityTokenPermission) (*CommunityChanges, error) {
  2615  	existed := o.tokenPermissionByID(permission.Id) != nil
  2616  
  2617  	if o.config.CommunityDescription.TokenPermissions == nil {
  2618  		o.config.CommunityDescription.TokenPermissions = make(map[string]*protobuf.CommunityTokenPermission)
  2619  	}
  2620  	o.config.CommunityDescription.TokenPermissions[permission.Id] = permission
  2621  
  2622  	changes := o.emptyCommunityChanges()
  2623  	if existed {
  2624  		changes.TokenPermissionsModified[permission.Id] = NewCommunityTokenPermission(permission)
  2625  	} else {
  2626  		changes.TokenPermissionsAdded[permission.Id] = NewCommunityTokenPermission(permission)
  2627  	}
  2628  
  2629  	return changes, nil
  2630  }
  2631  
  2632  func (o *Community) deleteTokenPermission(permissionID string) (*CommunityChanges, error) {
  2633  	permission, exists := o.config.CommunityDescription.TokenPermissions[permissionID]
  2634  	if !exists {
  2635  		return nil, ErrTokenPermissionNotFound
  2636  	}
  2637  
  2638  	delete(o.config.CommunityDescription.TokenPermissions, permissionID)
  2639  
  2640  	changes := o.emptyCommunityChanges()
  2641  
  2642  	changes.TokenPermissionsRemoved[permissionID] = NewCommunityTokenPermission(permission)
  2643  
  2644  	return changes, nil
  2645  }
  2646  
  2647  func (o *Community) DeclineRequestToJoin(dbRequest *RequestToJoin) (adminEventCreated bool, err error) {
  2648  	o.mutex.Lock()
  2649  	defer o.mutex.Unlock()
  2650  
  2651  	if !(o.IsControlNode() || o.hasPermissionToSendCommunityEvent(protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT)) {
  2652  		return adminEventCreated, ErrNotAuthorized
  2653  	}
  2654  
  2655  	if o.IsControlNode() {
  2656  		o.RemoveMembersFromOrg([]string{dbRequest.PublicKey})
  2657  		o.increaseClock()
  2658  	} else {
  2659  		err = o.addNewCommunityEvent(o.ToCommunityRequestToJoinRejectCommunityEvent(dbRequest.PublicKey, dbRequest.ToCommunityRequestToJoinProtobuf()))
  2660  		if err != nil {
  2661  			return adminEventCreated, err
  2662  		}
  2663  
  2664  		adminEventCreated = true
  2665  	}
  2666  
  2667  	return adminEventCreated, err
  2668  }
  2669  
  2670  func (o *Community) validateEvent(event *CommunityEvent, signer *ecdsa.PublicKey) error {
  2671  	err := event.Validate()
  2672  	if err != nil {
  2673  		return err
  2674  	}
  2675  
  2676  	eventSender := o.getMember(signer)
  2677  	if eventSender == nil {
  2678  		return ErrMemberNotFound
  2679  	}
  2680  
  2681  	eventTargetRoles := []protobuf.CommunityMember_Roles{}
  2682  	eventTargetPk, err := common.HexToPubkey(event.MemberToAction)
  2683  	if err == nil {
  2684  		eventTarget := o.getMember(eventTargetPk)
  2685  		if eventTarget != nil {
  2686  			eventTargetRoles = eventTarget.Roles
  2687  		}
  2688  	}
  2689  
  2690  	if !RolesAuthorizedToPerformEvent(eventSender.Roles, eventTargetRoles, event) {
  2691  		return ErrNotAuthorized
  2692  	}
  2693  
  2694  	return nil
  2695  }
  2696  
  2697  func (o *Community) ValidateEvent(event *CommunityEvent, signer *ecdsa.PublicKey) error {
  2698  	o.mutex.Lock()
  2699  	defer o.mutex.Unlock()
  2700  	return o.validateEvent(event, signer)
  2701  }
  2702  
  2703  func (o *Community) MemberCanManageToken(member *ecdsa.PublicKey, token *community_token.CommunityToken) bool {
  2704  	return o.IsMemberOwner(member) || o.IsControlNode() || (o.IsMemberTokenMaster(member) &&
  2705  		token.PrivilegesLevel != community_token.OwnerLevel && token.PrivilegesLevel != community_token.MasterLevel)
  2706  }
  2707  
  2708  func CommunityDescriptionTokenOwnerChainID(description *protobuf.CommunityDescription) uint64 {
  2709  	if description == nil {
  2710  		return 0
  2711  	}
  2712  
  2713  	// We look in TokenPermissions for a token that grants BECOME_TOKEN_OWNER rights
  2714  	// There should be only one, and it's only a single chainID
  2715  	for _, p := range description.TokenPermissions {
  2716  		if p.Type == protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER && len(p.TokenCriteria) != 0 {
  2717  
  2718  			for _, criteria := range p.TokenCriteria {
  2719  				for chainID := range criteria.ContractAddresses {
  2720  					return chainID
  2721  				}
  2722  			}
  2723  		}
  2724  	}
  2725  
  2726  	return 0
  2727  }
  2728  
  2729  func HasTokenOwnership(description *protobuf.CommunityDescription) bool {
  2730  	return uint64(0) != CommunityDescriptionTokenOwnerChainID(description)
  2731  }