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 }