github.com/status-im/status-go@v1.1.0/protocol/messenger_communities.go (about) 1 package protocol 2 3 import ( 4 "context" 5 "crypto/ecdsa" 6 "database/sql" 7 "encoding/json" 8 "errors" 9 "fmt" 10 "strings" 11 "sync" 12 "time" 13 14 "golang.org/x/exp/slices" 15 "golang.org/x/time/rate" 16 17 "github.com/golang/protobuf/proto" 18 "github.com/google/uuid" 19 20 gethcommon "github.com/ethereum/go-ethereum/common" 21 "github.com/ethereum/go-ethereum/common/hexutil" 22 23 "go.uber.org/zap" 24 25 utils "github.com/status-im/status-go/common" 26 27 "github.com/status-im/status-go/account" 28 multiaccountscommon "github.com/status-im/status-go/multiaccounts/common" 29 30 "github.com/status-im/status-go/eth-node/crypto" 31 "github.com/status-im/status-go/eth-node/types" 32 "github.com/status-im/status-go/images" 33 "github.com/status-im/status-go/multiaccounts/accounts" 34 "github.com/status-im/status-go/protocol/common" 35 "github.com/status-im/status-go/protocol/common/shard" 36 "github.com/status-im/status-go/protocol/communities" 37 "github.com/status-im/status-go/protocol/communities/token" 38 "github.com/status-im/status-go/protocol/discord" 39 "github.com/status-im/status-go/protocol/encryption" 40 "github.com/status-im/status-go/protocol/protobuf" 41 "github.com/status-im/status-go/protocol/requests" 42 "github.com/status-im/status-go/protocol/transport" 43 v1protocol "github.com/status-im/status-go/protocol/v1" 44 localnotifications "github.com/status-im/status-go/services/local-notifications" 45 "github.com/status-im/status-go/services/wallet/bigint" 46 "github.com/status-im/status-go/signal" 47 ) 48 49 // 7 days interval 50 var messageArchiveInterval = 7 * 24 * time.Hour 51 52 // 1 day interval 53 var updateActiveMembersInterval = 24 * time.Hour 54 55 // 1 day interval 56 var grantUpdateInterval = 24 * time.Hour 57 58 // 4 hours interval 59 var grantInvokesProfileDispatchInterval = 4 * time.Hour 60 61 const discordTimestampLayout = time.RFC3339 62 63 const ( 64 importSlowRate = time.Second / 1 65 importFastRate = time.Second / 100 66 importMessagesChunkSize = 10 67 importInitialDelay = time.Minute * 5 68 ) 69 70 const ( 71 maxChunkSizeMessages = 1000 72 maxChunkSizeBytes = 1500000 73 ) 74 75 const ( 76 ErrOwnerTokenNeeded = "Owner token is needed" // #nosec G101 77 ErrMissingCommunityID = "CommunityID has to be provided" 78 ErrForbiddenProfileOrWatchOnlyAccount = "Cannot join a community using profile chat or watch-only account" 79 ErrSigningJoinRequestForKeycardAccounts = "Signing a joining community request for accounts migrated to keycard must be done with a keycard" 80 ErrNotPartOfCommunity = "Not part of the community" 81 ErrNotAdminOrOwner = "Not admin or owner" 82 ErrSignerIsNil = "Signer can't be nil" 83 ErrSyncMessagesSentByNonControlNode = "Accepted/requested to join sync messages can be send only by the control node" 84 ErrReceiverIsNil = "Receiver can't be nil" 85 ) 86 87 type FetchCommunityRequest struct { 88 // CommunityKey should be either a public or a private community key 89 CommunityKey string `json:"communityKey"` 90 Shard *shard.Shard `json:"shard"` 91 TryDatabase bool `json:"tryDatabase"` 92 WaitForResponse bool `json:"waitForResponse"` 93 } 94 95 func (r *FetchCommunityRequest) Validate() error { 96 if len(r.CommunityKey) <= 2 { 97 return fmt.Errorf("community key is too short") 98 } 99 if _, err := types.DecodeHex(r.CommunityKey); err != nil { 100 return fmt.Errorf("invalid community key") 101 } 102 return nil 103 } 104 105 func (r *FetchCommunityRequest) getCommunityID() string { 106 return GetCommunityIDFromKey(r.CommunityKey) 107 } 108 109 func GetCommunityIDFromKey(communityKey string) string { 110 // Check if the key is a private key. strip the 0x at the start 111 if privateKey, err := crypto.HexToECDSA(communityKey[2:]); err == nil { 112 // It is a privateKey 113 return types.HexBytes(crypto.CompressPubkey(&privateKey.PublicKey)).String() 114 } 115 116 // Not a private key, use the public key 117 return communityKey 118 } 119 120 func (m *Messenger) publishOrg(org *communities.Community, shouldRekey bool) error { 121 if org == nil { 122 return nil 123 } 124 125 m.logger.Debug("publishing community", 126 zap.Uint64("clock", org.Clock()), 127 zap.String("communityID", org.IDString()), 128 zap.Any("community", org), 129 ) 130 131 payload, err := org.MarshaledDescription() 132 133 if err != nil { 134 return err 135 } 136 137 rawMessage := common.RawMessage{ 138 Payload: payload, 139 Sender: org.PrivateKey(), 140 // we don't want to wrap in an encryption layer message 141 SkipEncryptionLayer: true, 142 CommunityID: org.ID(), 143 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, 144 PubsubTopic: org.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic 145 Priority: &common.HighPriority, 146 } 147 if org.Encrypted() { 148 members := org.GetMemberPubkeys() 149 if err != nil { 150 return err 151 } 152 rawMessage.CommunityKeyExMsgType = common.KeyExMsgRekey 153 // This should be the one that it was used to encrypt this community 154 rawMessage.HashRatchetGroupID = org.ID() 155 rawMessage.Recipients = members 156 } 157 messageID, err := m.sender.SendPublic(context.Background(), org.IDString(), rawMessage) 158 if err == nil { 159 m.logger.Debug("published community", 160 zap.String("pubsubTopic", org.PubsubTopic()), 161 zap.String("communityID", org.IDString()), 162 zap.String("messageID", hexutil.Encode(messageID)), 163 zap.Uint64("clock", org.Clock()), 164 ) 165 } 166 return err 167 } 168 169 func (m *Messenger) publishCommunityEvents(community *communities.Community, msg *communities.CommunityEventsMessage) error { 170 m.logger.Debug("publishing community events", zap.String("admin-id", common.PubkeyToHex(&m.identity.PublicKey)), zap.Any("event", msg)) 171 172 payload, err := msg.Marshal() 173 if err != nil { 174 return err 175 } 176 177 rawMessage := common.RawMessage{ 178 Payload: payload, 179 Sender: m.identity, 180 // we don't want to wrap in an encryption layer message 181 SkipEncryptionLayer: true, 182 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_EVENTS_MESSAGE, 183 PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic 184 Priority: &common.LowPriority, 185 } 186 187 // TODO: resend in case of failure? 188 _, err = m.sender.SendPublic(context.Background(), types.EncodeHex(msg.CommunityID), rawMessage) 189 return err 190 } 191 192 func (m *Messenger) publishCommunityPrivilegedMemberSyncMessage(msg *communities.CommunityPrivilegedMemberSyncMessage) error { 193 community, err := m.GetCommunityByID(msg.CommunityPrivilegedUserSyncMessage.CommunityId) 194 if err != nil { 195 return err 196 } 197 198 m.logger.Debug("publishing privileged user sync message", 199 zap.Any("receivers", msg.Receivers), zap.Any("type", msg.CommunityPrivilegedUserSyncMessage.Type)) 200 201 payload, err := proto.Marshal(msg.CommunityPrivilegedUserSyncMessage) 202 if err != nil { 203 return err 204 } 205 206 rawMessage := &common.RawMessage{ 207 Payload: payload, 208 Sender: community.PrivateKey(), 209 SkipEncryptionLayer: true, 210 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_PRIVILEGED_USER_SYNC_MESSAGE, 211 } 212 213 for _, receivers := range msg.Receivers { 214 _, err = m.sender.SendPrivate(context.Background(), receivers, rawMessage) 215 } 216 217 return err 218 } 219 220 func (m *Messenger) handleCommunitiesHistoryArchivesSubscription(c chan *communities.Subscription) { 221 222 go func() { 223 for { 224 select { 225 case sub, more := <-c: 226 if !more { 227 return 228 } 229 230 if sub.CreatingHistoryArchivesSignal != nil { 231 m.config.messengerSignalsHandler.CreatingHistoryArchives(sub.CreatingHistoryArchivesSignal.CommunityID) 232 } 233 234 if sub.HistoryArchivesCreatedSignal != nil { 235 m.config.messengerSignalsHandler.HistoryArchivesCreated( 236 sub.HistoryArchivesCreatedSignal.CommunityID, 237 sub.HistoryArchivesCreatedSignal.From, 238 sub.HistoryArchivesCreatedSignal.To, 239 ) 240 } 241 242 if sub.NoHistoryArchivesCreatedSignal != nil { 243 m.config.messengerSignalsHandler.NoHistoryArchivesCreated( 244 sub.NoHistoryArchivesCreatedSignal.CommunityID, 245 sub.NoHistoryArchivesCreatedSignal.From, 246 sub.NoHistoryArchivesCreatedSignal.To, 247 ) 248 } 249 250 if sub.HistoryArchivesSeedingSignal != nil { 251 252 m.config.messengerSignalsHandler.HistoryArchivesSeeding(sub.HistoryArchivesSeedingSignal.CommunityID) 253 254 c, err := m.communitiesManager.GetByIDString(sub.HistoryArchivesSeedingSignal.CommunityID) 255 if err != nil { 256 m.logger.Debug("failed to retrieve community by id string", zap.Error(err)) 257 } 258 259 if c.IsControlNode() { 260 err := m.dispatchMagnetlinkMessage(sub.HistoryArchivesSeedingSignal.CommunityID) 261 if err != nil { 262 m.logger.Debug("failed to dispatch magnetlink message", zap.Error(err)) 263 } 264 } 265 } 266 267 if sub.HistoryArchivesUnseededSignal != nil { 268 m.config.messengerSignalsHandler.HistoryArchivesUnseeded(sub.HistoryArchivesUnseededSignal.CommunityID) 269 } 270 271 if sub.HistoryArchiveDownloadedSignal != nil { 272 m.config.messengerSignalsHandler.HistoryArchiveDownloaded( 273 sub.HistoryArchiveDownloadedSignal.CommunityID, 274 sub.HistoryArchiveDownloadedSignal.From, 275 sub.HistoryArchiveDownloadedSignal.To, 276 ) 277 } 278 279 if sub.DownloadingHistoryArchivesFinishedSignal != nil { 280 m.config.messengerSignalsHandler.DownloadingHistoryArchivesFinished(sub.DownloadingHistoryArchivesFinishedSignal.CommunityID) 281 } 282 283 if sub.DownloadingHistoryArchivesStartedSignal != nil { 284 m.config.messengerSignalsHandler.DownloadingHistoryArchivesStarted(sub.DownloadingHistoryArchivesStartedSignal.CommunityID) 285 } 286 287 if sub.ImportingHistoryArchiveMessagesSignal != nil { 288 m.config.messengerSignalsHandler.ImportingHistoryArchiveMessages(sub.ImportingHistoryArchiveMessagesSignal.CommunityID) 289 } 290 291 case <-m.quit: 292 return 293 } 294 } 295 }() 296 } 297 298 // handleCommunitiesSubscription handles events from communities 299 func (m *Messenger) handleCommunitiesSubscription(c chan *communities.Subscription) { 300 var lastPublished int64 301 // We check every 5 minutes if we need to publish 302 ticker := time.NewTicker(5 * time.Minute) 303 304 recentlyPublishedOrgs := make(map[string]*communities.Community, 0) 305 306 publishOrgAndDistributeEncryptionKeys := func(community *communities.Community) { 307 recentlyPublishedOrg := recentlyPublishedOrgs[community.IDString()] 308 309 if recentlyPublishedOrg != nil && community.Clock() < recentlyPublishedOrg.Clock() { 310 return 311 } 312 313 // evaluate and distribute encryption keys (if any) 314 encryptionKeyActions := communities.EvaluateCommunityEncryptionKeyActions(recentlyPublishedOrg, community) 315 err := m.communitiesKeyDistributor.Distribute(community, encryptionKeyActions) 316 if err != nil { 317 m.logger.Warn("failed to distribute encryption keys", zap.Error(err)) 318 } 319 320 shouldRekey := encryptionKeyActions.CommunityKeyAction.ActionType == communities.EncryptionKeyRekey 321 if community.Encrypted() { 322 clock := community.Clock() 323 clock++ 324 userKicked := &protobuf.CommunityUserKicked{ 325 Clock: clock, 326 CommunityId: community.ID(), 327 } 328 329 for pkString := range encryptionKeyActions.CommunityKeyAction.RemovedMembers { 330 pk, err := common.HexToPubkey(pkString) 331 if err != nil { 332 m.logger.Error("failed to decode public key", zap.Error(err), zap.String("pk", pkString)) 333 } 334 payload, err := proto.Marshal(userKicked) 335 if err != nil { 336 m.logger.Error("failed to marshal user kicked message", zap.Error(err)) 337 continue 338 } 339 340 rawMessage := &common.RawMessage{ 341 Payload: payload, 342 Sender: community.PrivateKey(), 343 SkipEncryptionLayer: true, 344 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_USER_KICKED, 345 PubsubTopic: shard.DefaultNonProtectedPubsubTopic(), 346 } 347 348 _, err = m.sender.SendPrivate(context.Background(), pk, rawMessage) 349 if err != nil { 350 m.logger.Error("failed to send used kicked message", zap.Error(err)) 351 continue 352 } 353 354 } 355 356 } 357 358 err = m.publishOrg(community, shouldRekey) 359 if err != nil { 360 m.logger.Warn("failed to publish org", zap.Error(err)) 361 return 362 } 363 m.logger.Debug("published org") 364 365 // publish shard information 366 err = m.sendPublicCommunityShardInfo(community) 367 if err != nil { 368 m.logger.Warn("failed to publish public shard info", zap.Error(err)) 369 return 370 } 371 372 // signal client with published community 373 if m.config.messengerSignalsHandler != nil { 374 if recentlyPublishedOrg == nil || community.Clock() > recentlyPublishedOrg.Clock() { 375 response := &MessengerResponse{} 376 response.AddCommunity(community) 377 m.config.messengerSignalsHandler.MessengerResponse(response) 378 } 379 } 380 381 recentlyPublishedOrgs[community.IDString()] = community.CreateDeepCopy() 382 } 383 384 go func() { 385 for { 386 select { 387 case sub, more := <-c: 388 if !more { 389 return 390 } 391 if sub.Community != nil { 392 if sub.Community == nil { 393 continue 394 } 395 // NOTE: because we use a pointer here, there's a race condition where the community would be updated before it's compared to the previous one. 396 // This results in keys not being propagated as the copy would not see any changes 397 communityCopy := sub.Community.CreateDeepCopy() 398 399 publishOrgAndDistributeEncryptionKeys(communityCopy) 400 } 401 402 if sub.CommunityEventsMessage != nil { 403 err := m.publishCommunityEvents(sub.Community, sub.CommunityEventsMessage) 404 if err != nil { 405 m.logger.Warn("failed to publish community events", zap.Error(err)) 406 } 407 } 408 409 if sub.AcceptedRequestsToJoin != nil { 410 for _, requestID := range sub.AcceptedRequestsToJoin { 411 accept := &requests.AcceptRequestToJoinCommunity{ 412 ID: requestID, 413 } 414 response, err := m.AcceptRequestToJoinCommunity(accept) 415 if err != nil { 416 m.logger.Warn("failed to accept request to join ", zap.Error(err)) 417 } 418 if m.config.messengerSignalsHandler != nil { 419 m.config.messengerSignalsHandler.MessengerResponse(response) 420 } 421 } 422 } 423 424 if sub.RejectedRequestsToJoin != nil { 425 for _, requestID := range sub.RejectedRequestsToJoin { 426 reject := &requests.DeclineRequestToJoinCommunity{ 427 ID: requestID, 428 } 429 response, err := m.DeclineRequestToJoinCommunity(reject) 430 if err != nil { 431 m.logger.Warn("failed to decline request to join ", zap.Error(err)) 432 } 433 if m.config.messengerSignalsHandler != nil { 434 m.config.messengerSignalsHandler.MessengerResponse(response) 435 } 436 } 437 } 438 439 if sub.CommunityPrivilegedMemberSyncMessage != nil { 440 if err := m.publishCommunityPrivilegedMemberSyncMessage(sub.CommunityPrivilegedMemberSyncMessage); err != nil { 441 m.logger.Warn("failed to publish community private members sync message", zap.Error(err)) 442 } 443 } 444 if sub.TokenCommunityValidated != nil { 445 state := m.buildMessageState() 446 communityResponse := sub.TokenCommunityValidated 447 448 err := m.handleCommunityResponse(state, communityResponse) 449 if err != nil { 450 m.logger.Error("failed to handle community response", zap.Error(err)) 451 } 452 453 m.processCommunityChanges(state) 454 455 _, err = m.saveDataAndPrepareResponse(state) 456 if err != nil { 457 m.logger.Error("failed to save data and prepare response") 458 } 459 460 if m.config.messengerSignalsHandler != nil { 461 m.config.messengerSignalsHandler.MessengerResponse(state.Response) 462 } 463 } 464 465 case <-ticker.C: 466 // If we are not online, we don't even try 467 if !m.Online() { 468 continue 469 } 470 471 // If not enough time has passed since last advertisement, we skip this 472 if time.Now().Unix()-lastPublished < communityAdvertiseIntervalSecond { 473 continue 474 } 475 476 controlledCommunities, err := m.communitiesManager.Controlled() 477 if err != nil { 478 m.logger.Warn("failed to retrieve orgs", zap.Error(err)) 479 } 480 481 for idx := range controlledCommunities { 482 org := controlledCommunities[idx] 483 _, beingImported := m.importingCommunities[org.IDString()] 484 if !beingImported { 485 publishOrgAndDistributeEncryptionKeys(org) 486 } 487 } 488 489 // set lastPublished 490 lastPublished = time.Now().Unix() 491 492 case <-m.quit: 493 ticker.Stop() 494 return 495 } 496 } 497 }() 498 } 499 500 func (m *Messenger) updateCommunitiesActiveMembersPeriodically() { 501 communitiesLastUpdated := make(map[string]int64) 502 503 // We check every 5 minutes if we need to update 504 ticker := time.NewTicker(5 * time.Minute) 505 506 go func() { 507 for { 508 select { 509 case <-ticker.C: 510 controlledCommunities, err := m.communitiesManager.Controlled() 511 if err != nil { 512 m.logger.Error("failed to update community active members count", zap.Error(err)) 513 } 514 515 for _, community := range controlledCommunities { 516 lastUpdated, ok := communitiesLastUpdated[community.IDString()] 517 if !ok { 518 lastUpdated = 0 519 } 520 521 // If not enough time has passed since last update, we skip this 522 if time.Now().Unix()-lastUpdated < int64(updateActiveMembersInterval.Seconds()) { 523 continue 524 } 525 526 if err := m.updateCommunityActiveMembers(community.IDString()); err == nil { 527 communitiesLastUpdated[community.IDString()] = time.Now().Unix() 528 529 // Perf: ensure `updateCommunityActiveMembers` is not called few times in a row 530 // Next communities will be handled in subsequent ticks 531 break 532 } else { 533 m.logger.Error("failed to update community active members count", zap.Error(err)) 534 } 535 } 536 537 case <-m.quit: 538 ticker.Stop() 539 return 540 } 541 } 542 }() 543 } 544 545 func (m *Messenger) HandleCommunityUpdateGrant(state *ReceivedMessageState, message *protobuf.CommunityUpdateGrant, statusMessage *v1protocol.StatusMessage) error { 546 community, err := m.communitiesManager.GetByID(message.CommunityId) 547 if err != nil { 548 return err 549 } 550 551 grant, err := m.encryptor.DecryptCommunityGrant(m.identity, state.CurrentMessageState.PublicKey, message.Grants) 552 if err != nil { 553 return err 554 } 555 556 return m.handleCommunityGrant(community, grant, message.Timestamp) 557 } 558 559 func (m *Messenger) HandleCommunityEncryptionKeysRequest(state *ReceivedMessageState, message *protobuf.CommunityEncryptionKeysRequest, statusMessage *v1protocol.StatusMessage) error { 560 community, err := m.communitiesManager.GetByID(message.CommunityId) 561 if err != nil { 562 return err 563 } 564 565 if !community.IsControlNode() { 566 return communities.ErrNotControlNode 567 } 568 signer := state.CurrentMessageState.PublicKey 569 return m.handleCommunityEncryptionKeysRequest(community, message.ChatIds, signer) 570 } 571 572 func (m *Messenger) HandleCommunitySharedAddressesRequest(state *ReceivedMessageState, message *protobuf.CommunitySharedAddressesRequest, statusMessage *v1protocol.StatusMessage) error { 573 community, err := m.communitiesManager.GetByID(message.CommunityId) 574 if err != nil { 575 return err 576 } 577 578 if !community.IsControlNode() { 579 return communities.ErrNotControlNode 580 } 581 signer := state.CurrentMessageState.PublicKey 582 return m.handleCommunitySharedAddressesRequest(state, community, signer) 583 } 584 585 func (m *Messenger) HandleCommunitySharedAddressesResponse(state *ReceivedMessageState, message *protobuf.CommunitySharedAddressesResponse, statusMessage *v1protocol.StatusMessage) error { 586 community, err := m.communitiesManager.GetByID(message.CommunityId) 587 if err != nil { 588 return err 589 } 590 591 signer := state.CurrentMessageState.PublicKey 592 return m.handleCommunitySharedAddressesResponse(state, community, signer, message.RevealedAccounts) 593 } 594 595 func (m *Messenger) HandleCommunityTokenAction(state *ReceivedMessageState, message *protobuf.CommunityTokenAction, statusMessage *v1protocol.StatusMessage) error { 596 return m.communityTokensService.ProcessCommunityTokenAction(message) 597 } 598 599 func (m *Messenger) handleCommunityEncryptionKeysRequest(community *communities.Community, channelIDs []string, signer *ecdsa.PublicKey) error { 600 if !community.HasMember(signer) { 601 return communities.ErrMemberNotFound 602 } 603 604 keyActions := &communities.EncryptionKeyActions{ 605 CommunityKeyAction: communities.EncryptionKeyAction{}, 606 ChannelKeysActions: map[string]communities.EncryptionKeyAction{}, 607 } 608 609 pkStr := common.PubkeyToHex(signer) 610 members := make(map[string]*protobuf.CommunityMember) 611 members[pkStr] = community.GetMember(signer) 612 613 if community.Encrypted() { 614 keyActions.CommunityKeyAction = communities.EncryptionKeyAction{ 615 ActionType: communities.EncryptionKeySendToMembers, 616 Members: members, 617 } 618 } 619 620 requestedChannelIDs := map[string]bool{} 621 for _, channelID := range channelIDs { 622 requestedChannelIDs[channelID] = true 623 } 624 625 for channelID, channel := range community.Chats() { 626 // Skip channels that weren't requested 627 if len(requestedChannelIDs) > 0 && !requestedChannelIDs[channelID] { 628 continue 629 } 630 631 channelMembers := channel.GetMembers() 632 member, exists := channelMembers[pkStr] 633 if exists && community.ChannelEncrypted(channelID) { 634 members[pkStr] = member 635 keyActions.ChannelKeysActions[channelID] = communities.EncryptionKeyAction{ 636 ActionType: communities.EncryptionKeySendToMembers, 637 Members: members, 638 } 639 } 640 } 641 642 err := m.communitiesKeyDistributor.Distribute(community, keyActions) 643 if err != nil { 644 m.logger.Error("failed to send community keys", zap.Error(err), zap.String("community ID", community.IDString())) 645 } 646 647 return nil 648 } 649 650 func (m *Messenger) handleCommunitySharedAddressesRequest(state *ReceivedMessageState, community *communities.Community, signer *ecdsa.PublicKey) error { 651 if !community.HasMember(signer) { 652 return communities.ErrMemberNotFound 653 } 654 655 pkStr := common.PubkeyToHex(signer) 656 657 revealedAccounts, err := m.communitiesManager.GetRevealedAddresses(community.ID(), pkStr) 658 if err != nil { 659 return err 660 } 661 662 usersSharedAddressesProto := &protobuf.CommunitySharedAddressesResponse{ 663 CommunityId: community.ID(), 664 RevealedAccounts: revealedAccounts, 665 } 666 667 payload, err := proto.Marshal(usersSharedAddressesProto) 668 if err != nil { 669 return err 670 } 671 672 rawMessage := common.RawMessage{ 673 Payload: payload, 674 Sender: community.PrivateKey(), 675 CommunityID: community.ID(), 676 SkipEncryptionLayer: true, 677 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_SHARED_ADDRESSES_RESPONSE, 678 PubsubTopic: shard.DefaultNonProtectedPubsubTopic(), 679 ResendType: common.ResendTypeRawMessage, 680 ResendMethod: common.ResendMethodSendPrivate, 681 Recipients: []*ecdsa.PublicKey{signer}, 682 } 683 684 _, err = m.sender.SendPrivate(context.Background(), signer, &rawMessage) 685 if err != nil { 686 return err 687 } 688 689 if community.IsPrivilegedMember(signer) { 690 memberRole := community.MemberRole(signer) 691 newPrivilegedMember := make(map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey) 692 newPrivilegedMember[memberRole] = []*ecdsa.PublicKey{signer} 693 if err = m.communitiesManager.ShareRequestsToJoinWithPrivilegedMembers(community, newPrivilegedMember); err != nil { 694 return err 695 } 696 } 697 698 return nil 699 } 700 701 func (m *Messenger) handleCommunitySharedAddressesResponse(state *ReceivedMessageState, community *communities.Community, signer *ecdsa.PublicKey, revealedAccounts []*protobuf.RevealedAccount) error { 702 isControlNodeMsg := common.IsPubKeyEqual(community.ControlNode(), signer) 703 if !isControlNodeMsg { 704 return errors.New(ErrSyncMessagesSentByNonControlNode) 705 } 706 707 requestID := communities.CalculateRequestID(common.PubkeyToHex(&m.identity.PublicKey), community.ID()) 708 err := m.communitiesManager.SaveRequestToJoinRevealedAddresses(requestID, revealedAccounts) 709 if err != nil { 710 return nil 711 } 712 713 requestsToJoin, err := m.communitiesManager.GetCommunityRequestsToJoinWithRevealedAddresses(community.ID()) 714 if err != nil { 715 return nil 716 } 717 718 state.Response.AddRequestsToJoinCommunity(requestsToJoin) 719 720 return nil 721 } 722 723 func (m *Messenger) handleCommunityGrant(community *communities.Community, grant []byte, clock uint64) error { 724 difference, err := m.communitiesManager.HandleCommunityGrant(community, grant, clock) 725 if err == communities.ErrGrantOlder || err == communities.ErrGrantExpired { 726 // Don't log an error for these cases 727 return nil 728 } 729 if err != nil { 730 return err 731 } 732 733 // if grant is significantly newer than the one we have, we should check the profile showcase 734 if time.Duration(difference)*time.Millisecond > grantInvokesProfileDispatchInterval { 735 err = m.UpdateProfileShowcaseCommunity(community) 736 if err != nil { 737 return err 738 } 739 } 740 return nil 741 } 742 743 func (m *Messenger) publishGroupGrantMessage(community *communities.Community, timestamp uint64, recipientGrants map[*ecdsa.PublicKey][]byte) error { 744 grants, err := m.encryptor.EncryptCommunityGrants(community.PrivateKey(), recipientGrants) 745 if err != nil { 746 return err 747 } 748 749 message := &protobuf.CommunityUpdateGrant{ 750 Timestamp: timestamp, 751 CommunityId: community.ID(), 752 Grants: grants, 753 } 754 755 payload, err := proto.Marshal(message) 756 if err != nil { 757 return err 758 } 759 760 rawMessage := common.RawMessage{ 761 Payload: payload, 762 Sender: community.PrivateKey(), 763 SkipEncryptionLayer: true, 764 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_UPDATE_GRANT, 765 PubsubTopic: community.PubsubTopic(), 766 Priority: &common.LowPriority, 767 } 768 769 _, err = m.sender.SendPublic(context.Background(), community.IDString(), rawMessage) 770 return err 771 } 772 773 func (m *Messenger) updateGrantsForControlledCommunities() { 774 controlledCommunities, err := m.communitiesManager.Controlled() 775 if err != nil { 776 m.logger.Error("failed fetch controlled communities for grants update", zap.Error(err)) 777 } 778 779 for _, community := range controlledCommunities { 780 // Skip unencrypted communities 781 if !community.Encrypted() { 782 continue 783 } 784 785 memberGrants := map[*ecdsa.PublicKey][]byte{} 786 for memberKey := range community.Members() { 787 if memberKey == m.IdentityPublicKeyString() { 788 grant, err := community.BuildGrant(m.IdentityPublicKey(), "") 789 if err != nil { 790 m.logger.Error("can't build own grant for controlled community", zap.Error(err)) 791 } 792 793 err = m.handleCommunityGrant(community, grant, uint64(time.Now().UnixMilli())) 794 if err != nil { 795 m.logger.Error("error handling grant for controlled community", zap.Error(err)) 796 } 797 } else { 798 memberPubKey, err := common.HexToPubkey(memberKey) 799 if err != nil { 800 m.logger.Error("Pubkey decode ", zap.Error(err)) 801 } 802 803 grant, err := community.BuildGrant(memberPubKey, "") 804 if err != nil { 805 m.logger.Error("can't build member's grant for controlled community", zap.Error(err)) 806 } 807 808 memberGrants[memberPubKey] = grant 809 } 810 } 811 err = m.publishGroupGrantMessage(community, uint64(time.Now().UnixMilli()), memberGrants) 812 if err != nil { 813 m.logger.Error("failed to update grant for community members", zap.Error(err)) 814 } 815 } 816 } 817 818 func (m *Messenger) schedulePublishGrantsForControlledCommunities() { 819 // Send once immediately 820 m.updateGrantsForControlledCommunities() 821 822 ticker := time.NewTicker(grantUpdateInterval) 823 824 go func() { 825 for { 826 select { 827 case <-ticker.C: 828 m.updateGrantsForControlledCommunities() 829 case <-m.quit: 830 ticker.Stop() 831 return 832 } 833 } 834 }() 835 } 836 837 func (m *Messenger) CheckCommunitiesToUnmute() (*MessengerResponse, error) { 838 m.logger.Debug("watching communities to unmute") 839 response := &MessengerResponse{} 840 communities, err := m.communitiesManager.All() 841 currTime := time.Now() 842 if err != nil { 843 return nil, fmt.Errorf("couldn't get all communities: %v", err) 844 } 845 for _, community := range communities { 846 communityMuteTill := community.MuteTill() 847 848 if currTime.After(communityMuteTill) && !communityMuteTill.Equal(time.Time{}) && community.Muted() { 849 err := m.communitiesManager.SetMuted(community.ID(), false) 850 if err != nil { 851 m.logger.Info("CheckCommunitiesToUnmute err", zap.Any("Couldn't unmute community", err)) 852 break 853 } 854 855 err = m.MuteCommunityTill(community.ID(), time.Time{}) 856 if err != nil { 857 m.logger.Info("MuteCommunityTill err", zap.Any("Could not set mute community till", err)) 858 break 859 } 860 861 unmutedCommunity, err := m.communitiesManager.GetByID(community.ID()) 862 if err != nil { 863 return nil, err 864 } 865 response.AddCommunity(unmutedCommunity) 866 867 } 868 869 } 870 871 return response, nil 872 } 873 874 func (m *Messenger) updateCommunityActiveMembers(communityID string) error { 875 lastWeek := time.Now().AddDate(0, 0, -7).Unix() 876 count, err := m.persistence.CountActiveChattersInCommunity(communityID, lastWeek) 877 if err != nil { 878 return err 879 } 880 881 if err = m.communitiesManager.SetCommunityActiveMembersCount(communityID, uint64(count)); err != nil { 882 return err 883 } 884 885 m.logger.Debug("community active members updated", zap.String("communityID", communityID), zap.Uint("count", count)) 886 return nil 887 } 888 889 func (m *Messenger) Communities() ([]*communities.Community, error) { 890 return m.communitiesManager.All() 891 } 892 893 func (m *Messenger) ControlledCommunities() ([]*communities.Community, error) { 894 return m.communitiesManager.Controlled() 895 } 896 897 func (m *Messenger) JoinedCommunities() ([]*communities.Community, error) { 898 return m.communitiesManager.Joined() 899 } 900 901 func (m *Messenger) IsDisplayNameDupeOfCommunityMember(name string) (bool, error) { 902 controlled, err := m.communitiesManager.Controlled() 903 if err != nil { 904 return false, err 905 } 906 907 joined, err := m.communitiesManager.Joined() 908 if err != nil { 909 return false, err 910 } 911 912 for _, community := range append(controlled, joined...) { 913 for memberKey := range community.Members() { 914 contact := m.GetContactByID(memberKey) 915 if contact == nil { 916 continue 917 } 918 if strings.Compare(contact.DisplayName, name) == 0 { 919 return true, nil 920 } 921 } 922 } 923 return false, nil 924 } 925 926 func (m *Messenger) CommunityUpdateLastOpenedAt(communityID string) (int64, error) { 927 id, err := hexutil.Decode(communityID) 928 if err != nil { 929 return 0, err 930 } 931 currentTime := time.Now().Unix() 932 updatedCommunity, err := m.communitiesManager.CommunityUpdateLastOpenedAt(id, currentTime) 933 if err != nil { 934 return 0, err 935 } 936 err = m.syncCommunity(context.Background(), updatedCommunity, m.dispatchMessage) 937 if err != nil { 938 return 0, err 939 } 940 return currentTime, nil 941 } 942 943 func (m *Messenger) SpectatedCommunities() ([]*communities.Community, error) { 944 return m.communitiesManager.Spectated() 945 } 946 947 func (m *Messenger) initCommunityChats(community *communities.Community) ([]*Chat, error) { 948 logger := m.logger.Named("initCommunityChats") 949 publicFiltersToInit := m.DefaultFilters(community) 950 951 chats := CreateCommunityChats(community, m.getTimesource()) 952 953 for _, chat := range chats { 954 publicFiltersToInit = append(publicFiltersToInit, transport.FiltersToInitialize{ChatID: chat.ID, PubsubTopic: community.PubsubTopic()}) 955 956 } 957 958 // Load transport filters 959 filters, err := m.transport.InitPublicFilters(publicFiltersToInit) 960 if err != nil { 961 logger.Debug("m.transport.InitPublicFilters error", zap.Error(err)) 962 return nil, err 963 } 964 965 if community.IsControlNode() { 966 // Init the community filter so we can receive messages on the community 967 968 communityFilters, err := m.InitCommunityFilters([]transport.CommunityFilterToInitialize{{ 969 Shard: community.Shard(), 970 PrivKey: community.PrivateKey(), 971 }}) 972 973 if err != nil { 974 return nil, err 975 } 976 filters = append(filters, communityFilters...) 977 } 978 979 willSync, err := m.scheduleSyncFilters(filters) 980 if err != nil { 981 logger.Debug("m.scheduleSyncFilters error", zap.Error(err)) 982 return nil, err 983 } 984 985 if !willSync { 986 defaultSyncPeriod, err := m.settings.GetDefaultSyncPeriod() 987 if err != nil { 988 logger.Debug("m.settings.GetDefaultSyncPeriod error", zap.Error(err)) 989 return nil, err 990 } 991 992 timestamp := uint32(m.getTimesource().GetCurrentTime()/1000) - defaultSyncPeriod 993 for idx := range chats { 994 chats[idx].SyncedTo = timestamp 995 chats[idx].SyncedFrom = timestamp 996 } 997 } 998 999 if err = m.saveChats(chats); err != nil { 1000 logger.Debug("m.saveChats error", zap.Error(err)) 1001 return nil, err 1002 } 1003 1004 return chats, nil 1005 } 1006 1007 func (m *Messenger) initCommunitySettings(communityID types.HexBytes) (*communities.CommunitySettings, error) { 1008 communitySettings, err := m.communitiesManager.GetCommunitySettingsByID(communityID) 1009 if err != nil { 1010 return nil, err 1011 } 1012 if communitySettings != nil { 1013 return communitySettings, nil 1014 } 1015 1016 communitySettings = &communities.CommunitySettings{ 1017 CommunityID: communityID.String(), 1018 HistoryArchiveSupportEnabled: true, 1019 } 1020 1021 if err := m.communitiesManager.SaveCommunitySettings(*communitySettings); err != nil { 1022 return nil, err 1023 } 1024 1025 return communitySettings, nil 1026 } 1027 1028 func (m *Messenger) JoinCommunity(ctx context.Context, communityID types.HexBytes, forceJoin bool) (*MessengerResponse, error) { 1029 mr, err := m.joinCommunity(ctx, communityID, forceJoin) 1030 if err != nil { 1031 return nil, err 1032 } 1033 1034 if com, ok := mr.communities[communityID.String()]; ok { 1035 err = m.syncCommunity(context.Background(), com, m.dispatchMessage) 1036 if err != nil { 1037 return nil, err 1038 } 1039 } 1040 1041 return mr, nil 1042 } 1043 1044 func (m *Messenger) subscribeToCommunityShard(communityID []byte, shard *shard.Shard) error { 1045 if m.transport.WakuVersion() != 2 { 1046 return nil 1047 } 1048 1049 // TODO: this should probably be moved completely to transport once pubsub topic logic is implemented 1050 pubsubTopic := shard.PubsubTopic() 1051 1052 privK, err := m.transport.RetrievePubsubTopicKey(pubsubTopic) 1053 if err != nil { 1054 return err 1055 } 1056 1057 var pubK *ecdsa.PublicKey 1058 if privK != nil { 1059 pubK = &privK.PublicKey 1060 } 1061 1062 return m.transport.SubscribeToPubsubTopic(pubsubTopic, pubK) 1063 } 1064 1065 func (m *Messenger) unsubscribeFromShard(shard *shard.Shard) error { 1066 if m.transport.WakuVersion() != 2 { 1067 return nil 1068 } 1069 1070 // TODO: this should probably be moved completely to transport once pubsub topic logic is implemented 1071 1072 return m.transport.UnsubscribeFromPubsubTopic(shard.PubsubTopic()) 1073 } 1074 1075 func (m *Messenger) joinCommunity(ctx context.Context, communityID types.HexBytes, forceJoin bool) (*MessengerResponse, error) { 1076 logger := m.logger.Named("joinCommunity") 1077 response := &MessengerResponse{} 1078 community, _ := m.communitiesManager.GetByID(communityID) 1079 isCommunityMember := community.Joined() 1080 1081 community, err := m.communitiesManager.JoinCommunity(communityID, forceJoin) 1082 if err != nil { 1083 logger.Debug("m.communitiesManager.JoinCommunity error", zap.Error(err)) 1084 return nil, err 1085 } 1086 1087 // chats and settings are already initialized for spectated communities 1088 if !community.Spectated() { 1089 chats, err := m.initCommunityChats(community) 1090 if err != nil { 1091 return nil, err 1092 } 1093 response.AddChats(chats) 1094 1095 if _, err = m.initCommunitySettings(communityID); err != nil { 1096 return nil, err 1097 } 1098 1099 if err = m.subscribeToCommunityShard(community.ID(), community.Shard()); err != nil { 1100 return nil, err 1101 } 1102 } 1103 1104 communitySettings, err := m.communitiesManager.GetCommunitySettingsByID(communityID) 1105 if err != nil { 1106 return nil, err 1107 } 1108 1109 response.AddCommunity(community) 1110 response.AddCommunitySettings(communitySettings) 1111 1112 if err = m.reregisterForPushNotifications(); err != nil { 1113 return nil, err 1114 } 1115 1116 if err = m.sendCurrentUserStatusToCommunity(ctx, community); err != nil { 1117 logger.Debug("m.sendCurrentUserStatusToCommunity error", zap.Error(err)) 1118 return nil, err 1119 } 1120 1121 if err = m.PublishIdentityImage(); err != nil { 1122 return nil, err 1123 } 1124 1125 // Was applicant not a member and successfully joined? 1126 if !isCommunityMember && community.Joined() { 1127 joinedNotification := &localnotifications.Notification{ 1128 ID: gethcommon.Hash(types.BytesToHash([]byte(`you-joined-` + communityID.String()))), 1129 Title: community.Name(), 1130 Message: community.Name(), 1131 BodyType: localnotifications.CategoryCommunityJoined, 1132 Category: localnotifications.CategoryCommunityJoined, 1133 Deeplink: "status-app://cr/" + community.IDString(), 1134 Image: "", 1135 } 1136 response.AddNotification(joinedNotification) 1137 1138 // Activity Center notification 1139 requestID := communities.CalculateRequestID(common.PubkeyToHex(&m.identity.PublicKey), communityID) 1140 notification, err := m.persistence.GetActivityCenterNotificationByID(requestID) 1141 if err != nil { 1142 return nil, err 1143 } 1144 1145 if notification != nil && notification.MembershipStatus != ActivityCenterMembershipStatusAccepted { 1146 notification.MembershipStatus = ActivityCenterMembershipStatusAccepted 1147 notification.Read = false 1148 notification.Deleted = false 1149 1150 notification.UpdatedAt = m.GetCurrentTimeInMillis() 1151 err = m.addActivityCenterNotification(response, notification, nil) 1152 if err != nil { 1153 m.logger.Error("failed to update request to join accepted notification", zap.Error(err)) 1154 return nil, err 1155 } 1156 } 1157 } 1158 1159 return response, nil 1160 } 1161 1162 func (m *Messenger) SpectateCommunity(communityID types.HexBytes) (*MessengerResponse, error) { 1163 logger := m.logger.Named("SpectateCommunity") 1164 1165 response := &MessengerResponse{} 1166 1167 community, err := m.communitiesManager.SpectateCommunity(communityID) 1168 if err != nil { 1169 logger.Debug("SpectateCommunity error", zap.Error(err)) 1170 return nil, err 1171 } 1172 1173 chats, err := m.initCommunityChats(community) 1174 if err != nil { 1175 return nil, err 1176 } 1177 response.AddChats(chats) 1178 1179 settings, err := m.initCommunitySettings(communityID) 1180 if err != nil { 1181 return nil, err 1182 } 1183 response.AddCommunitySettings(settings) 1184 1185 response.AddCommunity(community) 1186 1187 if err = m.subscribeToCommunityShard(community.ID(), community.Shard()); err != nil { 1188 return nil, err 1189 } 1190 1191 // sync community 1192 m.asyncRequestAllHistoricMessages() 1193 1194 return response, nil 1195 } 1196 1197 func (m *Messenger) MuteDuration(mutedType requests.MutingVariation) (time.Time, error) { 1198 var MuteTill time.Time 1199 1200 switch mutedType { 1201 case MuteTill1Min: 1202 MuteTill = time.Now().Add(MuteFor1MinDuration) 1203 case MuteFor15Min: 1204 MuteTill = time.Now().Add(MuteFor15MinsDuration) 1205 case MuteFor1Hr: 1206 MuteTill = time.Now().Add(MuteFor1HrsDuration) 1207 case MuteFor8Hr: 1208 MuteTill = time.Now().Add(MuteFor8HrsDuration) 1209 case MuteFor24Hr: 1210 MuteTill = time.Now().Add(MuteFor24HrsDuration) 1211 case MuteFor1Week: 1212 MuteTill = time.Now().Add(MuteFor1WeekDuration) 1213 default: 1214 MuteTill = time.Time{} 1215 } 1216 1217 muteTillTimeRemoveMs, err := time.Parse(time.RFC3339, MuteTill.Format(time.RFC3339)) 1218 if err != nil { 1219 return time.Time{}, err 1220 } 1221 1222 return muteTillTimeRemoveMs, nil 1223 } 1224 1225 func (m *Messenger) SetMuted(request *requests.MuteCommunity) error { 1226 if err := request.Validate(); err != nil { 1227 return err 1228 } 1229 1230 if request.MutedType == Unmuted { 1231 return m.communitiesManager.SetMuted(request.CommunityID, false) 1232 } 1233 1234 return m.communitiesManager.SetMuted(request.CommunityID, true) 1235 } 1236 1237 func (m *Messenger) MuteCommunityTill(communityID []byte, muteTill time.Time) error { 1238 return m.communitiesManager.MuteCommunityTill(communityID, muteTill) 1239 } 1240 1241 func (m *Messenger) MuteAllCommunityChats(request *requests.MuteCommunity) (time.Time, error) { 1242 return m.UpdateMuteCommunityStatus(request.CommunityID.String(), true, request.MutedType) 1243 } 1244 1245 func (m *Messenger) UnMuteAllCommunityChats(communityID string) (time.Time, error) { 1246 return m.UpdateMuteCommunityStatus(communityID, false, Unmuted) 1247 } 1248 1249 func (m *Messenger) UpdateMuteCommunityStatus(communityID string, muted bool, mutedType requests.MutingVariation) (time.Time, error) { 1250 community, err := m.communitiesManager.GetByIDString(communityID) 1251 if err != nil { 1252 return time.Time{}, err 1253 } 1254 1255 request := &requests.MuteCommunity{ 1256 CommunityID: community.ID(), 1257 MutedType: mutedType, 1258 } 1259 1260 err = m.SetMuted(request) 1261 if err != nil { 1262 return time.Time{}, err 1263 } 1264 1265 muteTill, err := m.MuteDuration(mutedType) 1266 if err != nil { 1267 return time.Time{}, err 1268 } 1269 1270 err = m.MuteCommunityTill(community.ID(), muteTill) 1271 1272 for _, chatID := range community.CommunityChatsIDs() { 1273 if muted { 1274 _, err := m.MuteChat(&requests.MuteChat{ChatID: communityID + chatID, MutedType: mutedType}) 1275 if err != nil { 1276 return time.Time{}, err 1277 } 1278 1279 } else { 1280 err = m.UnmuteChat(communityID + chatID) 1281 if err != nil { 1282 return time.Time{}, err 1283 } 1284 1285 } 1286 1287 if err != nil { 1288 return time.Time{}, err 1289 } 1290 } 1291 1292 return muteTill, err 1293 } 1294 1295 func (m *Messenger) SetMutePropertyOnChatsByCategory(request *requests.MuteCategory, muted bool) error { 1296 if err := request.Validate(); err != nil { 1297 return err 1298 } 1299 community, err := m.communitiesManager.GetByIDString(request.CommunityID) 1300 if err != nil { 1301 return err 1302 } 1303 1304 for _, chatID := range community.ChatsByCategoryID(request.CategoryID) { 1305 if muted { 1306 _, err = m.MuteChat(&requests.MuteChat{ChatID: request.CommunityID + chatID, MutedType: request.MutedType}) 1307 } else { 1308 err = m.UnmuteChat(request.CommunityID + chatID) 1309 } 1310 if err != nil { 1311 return err 1312 } 1313 } 1314 1315 return nil 1316 } 1317 1318 // Generates a single hash for each address that needs to be revealed to a community. 1319 // Each hash needs to be signed. 1320 // The order of retuned hashes corresponds to the order of addresses in addressesToReveal. 1321 func (m *Messenger) generateCommunityRequestsForSigning(memberPubKey string, communityID types.HexBytes, addressesToReveal []string, isEdit bool) ([]account.SignParams, error) { 1322 walletAccounts, err := m.settings.GetActiveAccounts() 1323 if err != nil { 1324 return nil, err 1325 } 1326 1327 containsAddress := func(addresses []string, targetAddress string) bool { 1328 for _, address := range addresses { 1329 if types.HexToAddress(address) == types.HexToAddress(targetAddress) { 1330 return true 1331 } 1332 } 1333 return false 1334 } 1335 1336 msgsToSign := make([]account.SignParams, 0) 1337 for _, walletAccount := range walletAccounts { 1338 if walletAccount.Chat || walletAccount.Type == accounts.AccountTypeWatch { 1339 continue 1340 } 1341 1342 if len(addressesToReveal) > 0 && !containsAddress(addressesToReveal, walletAccount.Address.Hex()) { 1343 continue 1344 } 1345 1346 requestID := []byte{} 1347 if !isEdit { 1348 requestID = communities.CalculateRequestID(memberPubKey, communityID) 1349 } 1350 msgsToSign = append(msgsToSign, account.SignParams{ 1351 Data: types.EncodeHex(crypto.Keccak256(m.IdentityPublicKeyCompressed(), communityID, requestID)), 1352 Address: walletAccount.Address.Hex(), 1353 }) 1354 } 1355 1356 return msgsToSign, nil 1357 } 1358 1359 func (m *Messenger) GenerateJoiningCommunityRequestsForSigning(memberPubKey string, communityID types.HexBytes, addressesToReveal []string) ([]account.SignParams, error) { 1360 if len(communityID) == 0 { 1361 return nil, errors.New(ErrMissingCommunityID) 1362 } 1363 return m.generateCommunityRequestsForSigning(memberPubKey, communityID, addressesToReveal, false) 1364 } 1365 1366 func (m *Messenger) GenerateEditCommunityRequestsForSigning(memberPubKey string, communityID types.HexBytes, addressesToReveal []string) ([]account.SignParams, error) { 1367 return m.generateCommunityRequestsForSigning(memberPubKey, communityID, addressesToReveal, true) 1368 } 1369 1370 // Signs the provided messages with the provided accounts and password. 1371 // Provided accounts must not belong to a keypair that is migrated to a keycard. 1372 // Otherwise, the signing will fail, cause such accounts should be signed with a keycard. 1373 func (m *Messenger) SignData(signParams []account.SignParams) ([]string, error) { 1374 signatures := make([]string, len(signParams)) 1375 for i, param := range signParams { 1376 if err := param.Validate(true); err != nil { 1377 return nil, err 1378 } 1379 1380 account, err := m.settings.GetAccountByAddress(types.HexToAddress(param.Address)) 1381 if err != nil { 1382 return nil, err 1383 } 1384 1385 if account.Chat || account.Type == accounts.AccountTypeWatch { 1386 return nil, errors.New(ErrForbiddenProfileOrWatchOnlyAccount) 1387 } 1388 1389 keypair, err := m.settings.GetKeypairByKeyUID(account.KeyUID) 1390 if err != nil { 1391 return nil, err 1392 } 1393 1394 if keypair.MigratedToKeycard() { 1395 return nil, errors.New(ErrSigningJoinRequestForKeycardAccounts) 1396 } 1397 1398 verifiedAccount, err := m.accountsManager.GetVerifiedWalletAccount(m.settings, param.Address, param.Password) 1399 if err != nil { 1400 return nil, err 1401 } 1402 1403 signature, err := m.accountsManager.Sign(param, verifiedAccount) 1404 if err != nil { 1405 return nil, err 1406 } 1407 1408 signatures[i] = types.EncodeHex(signature) 1409 } 1410 1411 return signatures, nil 1412 } 1413 1414 func (m *Messenger) RequestToJoinCommunity(request *requests.RequestToJoinCommunity) (*MessengerResponse, error) { 1415 // TODO: Because of changes that need to be done in tests, calling this function and providing `request` without `AddressesToReveal` 1416 // is not an error, but it should be. 1417 logger := m.logger.Named("RequestToJoinCommunity") 1418 logger.Debug("Addresses to reveal", zap.Any("Addresses:", request.AddressesToReveal)) 1419 1420 if err := request.Validate(); err != nil { 1421 logger.Debug("request failed to validate", zap.Error(err), zap.Any("request", request)) 1422 return nil, err 1423 } 1424 1425 community, err := m.communitiesManager.GetByID(request.CommunityID) 1426 if err != nil { 1427 return nil, err 1428 } 1429 1430 // We don't allow requesting access if already joined 1431 if community.Joined() { 1432 return nil, communities.ErrAlreadyJoined 1433 } 1434 1435 requestToJoin := m.communitiesManager.CreateRequestToJoin(request, m.account.GetCustomizationColor()) 1436 1437 if len(request.AddressesToReveal) > 0 { 1438 revealedAddresses := make([]gethcommon.Address, 0) 1439 for _, addr := range request.AddressesToReveal { 1440 revealedAddresses = append(revealedAddresses, gethcommon.HexToAddress(addr)) 1441 } 1442 1443 permissions, err := m.communitiesManager.CheckPermissionToJoin(request.CommunityID, revealedAddresses) 1444 if err != nil { 1445 return nil, err 1446 } 1447 if !permissions.Satisfied { 1448 return nil, communities.ErrPermissionToJoinNotSatisfied 1449 } 1450 1451 for _, accountAndChainIDs := range permissions.ValidCombinations { 1452 for i := range requestToJoin.RevealedAccounts { 1453 if gethcommon.HexToAddress(requestToJoin.RevealedAccounts[i].Address) == accountAndChainIDs.Address { 1454 requestToJoin.RevealedAccounts[i].ChainIds = accountAndChainIDs.ChainIDs 1455 } 1456 } 1457 } 1458 } 1459 1460 displayName, err := m.settings.DisplayName() 1461 if err != nil { 1462 return nil, err 1463 } 1464 1465 requestToJoinProto := &protobuf.CommunityRequestToJoin{ 1466 Clock: requestToJoin.Clock, 1467 EnsName: requestToJoin.ENSName, 1468 DisplayName: displayName, 1469 CommunityId: request.CommunityID, 1470 RevealedAccounts: requestToJoin.RevealedAccounts, 1471 CustomizationColor: multiaccountscommon.ColorToIDFallbackToBlue(requestToJoin.CustomizationColor), 1472 } 1473 1474 community, _, err = m.communitiesManager.SaveRequestToJoinAndCommunity(requestToJoin, community) 1475 if err != nil { 1476 return nil, err 1477 } 1478 err = m.syncCommunity(context.Background(), community, m.dispatchMessage) 1479 if err != nil { 1480 return nil, err 1481 } 1482 1483 payload, err := proto.Marshal(requestToJoinProto) 1484 if err != nil { 1485 return nil, err 1486 } 1487 1488 rawMessage := &common.RawMessage{ 1489 Payload: payload, 1490 CommunityID: community.ID(), 1491 ResendType: common.ResendTypeRawMessage, 1492 SkipEncryptionLayer: true, 1493 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN, 1494 PubsubTopic: shard.DefaultNonProtectedPubsubTopic(), 1495 Priority: &common.HighPriority, 1496 } 1497 1498 _, err = m.SendMessageToControlNode(community, rawMessage) 1499 if err != nil { 1500 return nil, err 1501 } 1502 1503 if rawMessage.ResendType == common.ResendTypeRawMessage { 1504 if _, err = m.AddRawMessageToWatch(rawMessage); err != nil { 1505 return nil, err 1506 } 1507 } 1508 1509 if !community.AutoAccept() { 1510 privilegedMembersSorted := community.GetFilteredPrivilegedMembers(map[string]struct{}{m.IdentityPublicKeyString(): {}}) 1511 privMembersArray := []*ecdsa.PublicKey{} 1512 1513 if rawMessage.ResendMethod != common.ResendMethodSendPrivate { 1514 privMembersArray = append(privMembersArray, privilegedMembersSorted[protobuf.CommunityMember_ROLE_OWNER]...) 1515 } 1516 1517 privMembersArray = append(privMembersArray, privilegedMembersSorted[protobuf.CommunityMember_ROLE_TOKEN_MASTER]...) 1518 privMembersArray = append(privMembersArray, privilegedMembersSorted[protobuf.CommunityMember_ROLE_ADMIN]...) 1519 1520 rawMessage.ResendMethod = common.ResendMethodSendPrivate 1521 rawMessage.ResendType = common.ResendTypeDataSync 1522 // MVDS only supports sending encrypted message 1523 rawMessage.SkipEncryptionLayer = false 1524 rawMessage.ID = "" 1525 rawMessage.Recipients = privMembersArray 1526 1527 // don't send revealed addresses to privileged members 1528 // tokenMaster and owner without community private key will receive them from control node 1529 requestToJoinProto.RevealedAccounts = make([]*protobuf.RevealedAccount, 0) 1530 payload, err = proto.Marshal(requestToJoinProto) 1531 if err != nil { 1532 return nil, err 1533 } 1534 rawMessage.Payload = payload 1535 1536 for _, member := range rawMessage.Recipients { 1537 rawMessage.Sender = nil 1538 _, err := m.sender.SendPrivate(context.Background(), member, rawMessage) 1539 if err != nil { 1540 return nil, err 1541 } 1542 } 1543 } 1544 1545 response := &MessengerResponse{} 1546 response.AddRequestToJoinCommunity(requestToJoin) 1547 response.AddCommunity(community) 1548 1549 // We send a push notification in the background 1550 go func() { 1551 if m.pushNotificationClient != nil { 1552 pks, err := community.CanManageUsersPublicKeys() 1553 if err != nil { 1554 m.logger.Error("failed to get pks", zap.Error(err)) 1555 return 1556 } 1557 for _, publicKey := range pks { 1558 pkString := common.PubkeyToHex(publicKey) 1559 _, err = m.pushNotificationClient.SendNotification(publicKey, nil, requestToJoin.ID, pkString, protobuf.PushNotification_REQUEST_TO_JOIN_COMMUNITY) 1560 if err != nil { 1561 m.logger.Error("error sending notification", zap.Error(err)) 1562 return 1563 } 1564 } 1565 } 1566 }() 1567 1568 // Activity center notification 1569 notification := &ActivityCenterNotification{ 1570 ID: types.FromHex(requestToJoin.ID.String()), 1571 Type: ActivityCenterNotificationTypeCommunityRequest, 1572 Timestamp: m.getTimesource().GetCurrentTime(), 1573 CommunityID: community.IDString(), 1574 MembershipStatus: ActivityCenterMembershipStatusPending, 1575 Read: true, 1576 Deleted: false, 1577 UpdatedAt: m.GetCurrentTimeInMillis(), 1578 } 1579 1580 err = m.addActivityCenterNotification(response, notification, nil) 1581 if err != nil { 1582 m.logger.Error("failed to save notification", zap.Error(err)) 1583 return nil, err 1584 } 1585 1586 for _, account := range requestToJoin.RevealedAccounts { 1587 err := m.settings.AddressWasShown(types.HexToAddress(account.Address)) 1588 if err != nil { 1589 return nil, err 1590 } 1591 } 1592 1593 return response, nil 1594 } 1595 1596 func (m *Messenger) EditSharedAddressesForCommunity(request *requests.EditSharedAddresses) (*MessengerResponse, error) { 1597 logger := m.logger.Named("EditSharedAddressesForCommunity") 1598 if err := request.Validate(); err != nil { 1599 logger.Debug("request failed to validate", zap.Error(err), zap.Any("request", request)) 1600 return nil, err 1601 } 1602 1603 community, err := m.communitiesManager.GetByID(request.CommunityID) 1604 if err != nil { 1605 return nil, err 1606 } 1607 1608 if !community.HasMember(m.IdentityPublicKey()) { 1609 return nil, errors.New(ErrNotPartOfCommunity) 1610 } 1611 1612 revealedAddresses := make([]gethcommon.Address, 0) 1613 for _, addr := range request.AddressesToReveal { 1614 revealedAddresses = append(revealedAddresses, gethcommon.HexToAddress(addr)) 1615 } 1616 1617 checkPermissionResponse, err := m.communitiesManager.CheckPermissionToJoin(community.ID(), revealedAddresses) 1618 if err != nil { 1619 return nil, err 1620 } 1621 1622 member := community.GetMember(m.IdentityPublicKey()) 1623 1624 requestToEditRevealedAccountsProto := &protobuf.CommunityEditSharedAddresses{ 1625 Clock: member.LastUpdateClock + 1, 1626 CommunityId: community.ID(), 1627 RevealedAccounts: make([]*protobuf.RevealedAccount, 0), 1628 } 1629 1630 for i := range request.AddressesToReveal { 1631 revealedAcc := &protobuf.RevealedAccount{ 1632 Address: request.AddressesToReveal[i], 1633 IsAirdropAddress: types.HexToAddress(request.AddressesToReveal[i]) == types.HexToAddress(request.AirdropAddress), 1634 Signature: request.Signatures[i], 1635 } 1636 1637 for _, accountAndChainIDs := range checkPermissionResponse.ValidCombinations { 1638 if accountAndChainIDs.Address == gethcommon.HexToAddress(request.AddressesToReveal[i]) { 1639 revealedAcc.ChainIds = accountAndChainIDs.ChainIDs 1640 break 1641 } 1642 } 1643 1644 requestToEditRevealedAccountsProto.RevealedAccounts = append(requestToEditRevealedAccountsProto.RevealedAccounts, revealedAcc) 1645 } 1646 1647 requestID := communities.CalculateRequestID(common.PubkeyToHex(&m.identity.PublicKey), request.CommunityID) 1648 err = m.communitiesManager.RemoveRequestToJoinRevealedAddresses(requestID) 1649 if err != nil { 1650 return nil, err 1651 } 1652 err = m.communitiesManager.SaveRequestToJoinRevealedAddresses(requestID, requestToEditRevealedAccountsProto.RevealedAccounts) 1653 if err != nil { 1654 return nil, err 1655 } 1656 1657 payload, err := proto.Marshal(requestToEditRevealedAccountsProto) 1658 if err != nil { 1659 return nil, err 1660 } 1661 1662 rawMessage := common.RawMessage{ 1663 Payload: payload, 1664 CommunityID: community.ID(), 1665 SkipEncryptionLayer: true, 1666 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_EDIT_SHARED_ADDRESSES, 1667 PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic 1668 ResendType: common.ResendTypeRawMessage, 1669 } 1670 1671 _, err = m.SendMessageToControlNode(community, &rawMessage) 1672 if err != nil { 1673 return nil, err 1674 } 1675 1676 if _, err = m.AddRawMessageToWatch(&rawMessage); err != nil { 1677 return nil, err 1678 } 1679 1680 response := &MessengerResponse{} 1681 response.AddCommunity(community) 1682 1683 return response, nil 1684 } 1685 1686 func (m *Messenger) PublishTokenActionToPrivilegedMembers(communityID []byte, chainID uint64, contractAddress string, actionType protobuf.CommunityTokenAction_ActionType) error { 1687 1688 community, err := m.communitiesManager.GetByID(communityID) 1689 if err != nil { 1690 return err 1691 } 1692 1693 tokenActionProto := &protobuf.CommunityTokenAction{ 1694 ChainId: chainID, 1695 ContractAddress: contractAddress, 1696 ActionType: actionType, 1697 } 1698 1699 payload, err := proto.Marshal(tokenActionProto) 1700 if err != nil { 1701 return err 1702 } 1703 1704 rawMessage := common.RawMessage{ 1705 Payload: payload, 1706 CommunityID: community.ID(), 1707 ResendType: common.ResendTypeRawMessage, 1708 ResendMethod: common.ResendMethodSendPrivate, 1709 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_TOKEN_ACTION, 1710 PubsubTopic: community.PubsubTopic(), 1711 } 1712 1713 skipMembers := make(map[string]struct{}) 1714 skipMembers[common.PubkeyToHex(&m.identity.PublicKey)] = struct{}{} 1715 privilegedMembers := community.GetFilteredPrivilegedMembers(skipMembers) 1716 1717 allRecipients := privilegedMembers[protobuf.CommunityMember_ROLE_OWNER] 1718 allRecipients = append(allRecipients, privilegedMembers[protobuf.CommunityMember_ROLE_TOKEN_MASTER]...) 1719 rawMessage.Recipients = allRecipients 1720 1721 for _, recipient := range rawMessage.Recipients { 1722 _, err := m.sender.SendPrivate(context.Background(), recipient, &rawMessage) 1723 if err != nil { 1724 return err 1725 } 1726 } 1727 1728 if len(allRecipients) > 0 { 1729 if _, err = m.AddRawMessageToWatch(&rawMessage); err != nil { 1730 return err 1731 } 1732 } 1733 1734 return nil 1735 } 1736 1737 func (m *Messenger) GetRevealedAccounts(communityID types.HexBytes, memberPk string) ([]*protobuf.RevealedAccount, error) { 1738 return m.communitiesManager.GetRevealedAddresses(communityID, memberPk) 1739 } 1740 1741 func (m *Messenger) GetRevealedAccountsForAllMembers(communityID types.HexBytes) (map[string][]*protobuf.RevealedAccount, error) { 1742 community, err := m.communitiesManager.GetByID(communityID) 1743 if err != nil { 1744 return nil, err 1745 } 1746 membersRevealedAccounts := map[string][]*protobuf.RevealedAccount{} 1747 for _, memberPubKey := range community.GetMemberPubkeys() { 1748 memberPubKeyStr := common.PubkeyToHex(memberPubKey) 1749 accounts, err := m.communitiesManager.GetRevealedAddresses(communityID, memberPubKeyStr) 1750 if err != nil { 1751 return nil, err 1752 } 1753 membersRevealedAccounts[memberPubKeyStr] = accounts 1754 } 1755 return membersRevealedAccounts, nil 1756 } 1757 1758 func (m *Messenger) CreateCommunityCategory(request *requests.CreateCommunityCategory) (*MessengerResponse, error) { 1759 if err := request.Validate(); err != nil { 1760 return nil, err 1761 } 1762 1763 var response MessengerResponse 1764 _, changes, err := m.communitiesManager.CreateCategory(request, true) 1765 if err != nil { 1766 return nil, err 1767 } 1768 response.AddCommunity(changes.Community) 1769 response.CommunityChanges = []*communities.CommunityChanges{changes} 1770 1771 return &response, nil 1772 } 1773 1774 func (m *Messenger) EditCommunityCategory(request *requests.EditCommunityCategory) (*MessengerResponse, error) { 1775 if err := request.Validate(); err != nil { 1776 return nil, err 1777 } 1778 1779 var response MessengerResponse 1780 community, changes, err := m.communitiesManager.EditCategory(request) 1781 if err != nil { 1782 return nil, err 1783 } 1784 response.AddCommunity(community) 1785 response.CommunityChanges = []*communities.CommunityChanges{changes} 1786 1787 return &response, nil 1788 } 1789 1790 func (m *Messenger) ReorderCommunityCategories(request *requests.ReorderCommunityCategories) (*MessengerResponse, error) { 1791 if err := request.Validate(); err != nil { 1792 return nil, err 1793 } 1794 1795 var response MessengerResponse 1796 community, changes, err := m.communitiesManager.ReorderCategories(request) 1797 if err != nil { 1798 return nil, err 1799 } 1800 response.AddCommunity(community) 1801 response.CommunityChanges = []*communities.CommunityChanges{changes} 1802 1803 return &response, nil 1804 } 1805 1806 func (m *Messenger) ReorderCommunityChat(request *requests.ReorderCommunityChat) (*MessengerResponse, error) { 1807 if err := request.Validate(); err != nil { 1808 return nil, err 1809 } 1810 1811 var response MessengerResponse 1812 community, changes, err := m.communitiesManager.ReorderChat(request) 1813 if err != nil { 1814 return nil, err 1815 } 1816 response.AddCommunity(community) 1817 response.CommunityChanges = []*communities.CommunityChanges{changes} 1818 1819 return &response, nil 1820 } 1821 1822 func (m *Messenger) DeleteCommunityCategory(request *requests.DeleteCommunityCategory) (*MessengerResponse, error) { 1823 if err := request.Validate(); err != nil { 1824 return nil, err 1825 } 1826 1827 var response MessengerResponse 1828 community, changes, err := m.communitiesManager.DeleteCategory(request) 1829 if err != nil { 1830 return nil, err 1831 } 1832 response.AddCommunity(community) 1833 response.CommunityChanges = []*communities.CommunityChanges{changes} 1834 1835 return &response, nil 1836 } 1837 1838 func (m *Messenger) CancelRequestToJoinCommunity(ctx context.Context, request *requests.CancelRequestToJoinCommunity) (*MessengerResponse, error) { 1839 if err := request.Validate(); err != nil { 1840 return nil, err 1841 } 1842 1843 requestToJoin, community, err := m.communitiesManager.CancelRequestToJoin(request) 1844 if err != nil { 1845 return nil, err 1846 } 1847 1848 displayName, err := m.settings.DisplayName() 1849 if err != nil { 1850 return nil, err 1851 } 1852 1853 cancelRequestToJoinProto := &protobuf.CommunityCancelRequestToJoin{ 1854 Clock: community.Clock(), 1855 EnsName: requestToJoin.ENSName, 1856 DisplayName: displayName, 1857 CommunityId: community.ID(), 1858 CustomizationColor: multiaccountscommon.ColorToIDFallbackToBlue(requestToJoin.CustomizationColor), 1859 } 1860 1861 payload, err := proto.Marshal(cancelRequestToJoinProto) 1862 if err != nil { 1863 return nil, err 1864 } 1865 1866 rawMessage := common.RawMessage{ 1867 Payload: payload, 1868 CommunityID: community.ID(), 1869 SkipEncryptionLayer: true, 1870 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_CANCEL_REQUEST_TO_JOIN, 1871 PubsubTopic: shard.DefaultNonProtectedPubsubTopic(), 1872 ResendType: common.ResendTypeRawMessage, 1873 Priority: &common.HighPriority, 1874 } 1875 1876 _, err = m.SendMessageToControlNode(community, &rawMessage) 1877 if err != nil { 1878 return nil, err 1879 } 1880 1881 // NOTE: rawMessage.ID is generated from payload + sender + messageType 1882 // rawMessage.ID will be the same for control node and privileged members, but for 1883 // community without owner token resend type is different 1884 // in order not to override msg to control node by message for privileged members, 1885 // we skip storing the same message for privileged members 1886 avoidDuplicateWatchingForPrivilegedMembers := community.AutoAccept() || rawMessage.ResendMethod != common.ResendMethodSendPrivate 1887 if avoidDuplicateWatchingForPrivilegedMembers { 1888 if _, err = m.AddRawMessageToWatch(&rawMessage); err != nil { 1889 return nil, err 1890 } 1891 } 1892 1893 if !community.AutoAccept() { 1894 // send cancelation to community admins also 1895 rawMessage.Payload = payload 1896 rawMessage.ResendMethod = common.ResendMethodSendPrivate 1897 1898 privilegedMembersSorted := community.GetFilteredPrivilegedMembers(map[string]struct{}{m.IdentityPublicKeyString(): {}}) 1899 privMembersArray := privilegedMembersSorted[protobuf.CommunityMember_ROLE_TOKEN_MASTER] 1900 privMembersArray = append(privMembersArray, privilegedMembersSorted[protobuf.CommunityMember_ROLE_ADMIN]...) 1901 1902 if !avoidDuplicateWatchingForPrivilegedMembers { 1903 // control node was added to the recipients during 'SendMessageToControlNode' 1904 rawMessage.Recipients = append(rawMessage.Recipients, privMembersArray...) 1905 } else { 1906 privMembersArray = append(privMembersArray, privilegedMembersSorted[protobuf.CommunityMember_ROLE_OWNER]...) 1907 rawMessage.Recipients = privMembersArray 1908 } 1909 1910 for _, privilegedMember := range privMembersArray { 1911 _, err := m.sender.SendPrivate(context.Background(), privilegedMember, &rawMessage) 1912 if err != nil { 1913 return nil, err 1914 } 1915 } 1916 1917 if !avoidDuplicateWatchingForPrivilegedMembers { 1918 if _, err = m.AddRawMessageToWatch(&rawMessage); err != nil { 1919 return nil, err 1920 } 1921 } 1922 } 1923 1924 response := &MessengerResponse{} 1925 response.AddCommunity(community) 1926 response.AddRequestToJoinCommunity(requestToJoin) 1927 1928 // delete activity center notification 1929 notification, err := m.persistence.GetActivityCenterNotificationByID(requestToJoin.ID) 1930 if err != nil { 1931 return nil, err 1932 } 1933 1934 if notification != nil { 1935 notification.IncrementUpdatedAt(m.getTimesource()) 1936 err = m.persistence.DeleteActivityCenterNotificationByID(types.FromHex(requestToJoin.ID.String()), notification.UpdatedAt) 1937 if err != nil { 1938 m.logger.Error("failed to delete notification from Activity Center", zap.Error(err)) 1939 return nil, err 1940 } 1941 1942 // set notification as deleted, so that the client will remove the activity center notification from UI 1943 notification.Deleted = true 1944 err = m.syncActivityCenterDeletedByIDs(ctx, []types.HexBytes{notification.ID}, notification.UpdatedAt) 1945 if err != nil { 1946 m.logger.Error("CancelRequestToJoinCommunity, failed to sync activity center notification as deleted", zap.Error(err)) 1947 return nil, err 1948 } 1949 response.AddActivityCenterNotification(notification) 1950 } 1951 1952 return response, nil 1953 } 1954 1955 func (m *Messenger) acceptRequestToJoinCommunity(requestToJoin *communities.RequestToJoin) (*MessengerResponse, error) { 1956 m.logger.Debug("accept request to join community", 1957 zap.String("community", requestToJoin.CommunityID.String()), 1958 zap.String("pubkey", requestToJoin.PublicKey)) 1959 1960 community, err := m.communitiesManager.AcceptRequestToJoin(requestToJoin) 1961 if err != nil { 1962 return nil, err 1963 } 1964 1965 if community.IsControlNode() { 1966 // If we are the control node, we send the response to the user 1967 pk, err := common.HexToPubkey(requestToJoin.PublicKey) 1968 if err != nil { 1969 return nil, err 1970 } 1971 1972 grant, err := community.BuildGrant(pk, "") 1973 if err != nil { 1974 return nil, err 1975 } 1976 1977 var key *ecdsa.PrivateKey 1978 if m.transport.WakuVersion() == 2 { 1979 key, err = m.transport.RetrievePubsubTopicKey(community.PubsubTopic()) 1980 if err != nil { 1981 return nil, err 1982 } 1983 } 1984 1985 encryptedDescription, err := community.EncryptedDescription() 1986 if err != nil { 1987 return nil, err 1988 } 1989 1990 requestToJoinResponseProto := &protobuf.CommunityRequestToJoinResponse{ 1991 Clock: community.Clock(), 1992 Accepted: true, 1993 CommunityId: community.ID(), 1994 Community: encryptedDescription, 1995 Grant: grant, 1996 ProtectedTopicPrivateKey: crypto.FromECDSA(key), 1997 Shard: community.Shard().Protobuffer(), 1998 } 1999 2000 // The purpose of this torrent code is to get the 'magnetlink' to populate 'requestToJoinResponseProto.MagnetUri' 2001 if m.archiveManager.IsReady() && m.archiveManager.TorrentFileExists(community.IDString()) { 2002 magnetlink, err := m.archiveManager.GetHistoryArchiveMagnetlink(community.ID()) 2003 if err != nil { 2004 m.logger.Warn("couldn't get magnet link for community", zap.Error(err)) 2005 return nil, err 2006 } 2007 requestToJoinResponseProto.MagnetUri = magnetlink 2008 } 2009 2010 payload, err := proto.Marshal(requestToJoinResponseProto) 2011 if err != nil { 2012 return nil, err 2013 } 2014 2015 rawMessage := &common.RawMessage{ 2016 Payload: payload, 2017 Sender: community.PrivateKey(), 2018 CommunityID: community.ID(), 2019 SkipEncryptionLayer: true, 2020 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN_RESPONSE, 2021 PubsubTopic: shard.DefaultNonProtectedPubsubTopic(), 2022 ResendType: common.ResendTypeRawMessage, 2023 ResendMethod: common.ResendMethodSendPrivate, 2024 Recipients: []*ecdsa.PublicKey{pk}, 2025 Priority: &common.HighPriority, 2026 } 2027 2028 // Non-tokenized community treat community public key as the control node, 2029 // tokenized community set control node to the public key of token owner. 2030 // MVDS doesn't support custom sender, and use the identity key for signing messages, 2031 // receiver will verify the message of community join response is signed by control node. 2032 if !community.PublicKey().Equal(community.ControlNode()) { 2033 rawMessage.ResendType = common.ResendTypeDataSync 2034 rawMessage.SkipEncryptionLayer = false 2035 rawMessage.Sender = nil 2036 } 2037 2038 if community.Encrypted() { 2039 rawMessage.HashRatchetGroupID = community.ID() 2040 rawMessage.CommunityKeyExMsgType = common.KeyExMsgReuse 2041 } 2042 2043 _, err = m.sender.SendPrivate(context.Background(), pk, rawMessage) 2044 if err != nil { 2045 return nil, err 2046 } 2047 2048 if rawMessage.ResendType == common.ResendTypeRawMessage { 2049 if _, err = m.AddRawMessageToWatch(rawMessage); err != nil { 2050 return nil, err 2051 } 2052 } 2053 } 2054 2055 response := &MessengerResponse{} 2056 response.AddCommunity(community) 2057 response.AddRequestToJoinCommunity(requestToJoin) 2058 2059 // Update existing notification 2060 notification, err := m.persistence.GetActivityCenterNotificationByID(requestToJoin.ID) 2061 if err != nil { 2062 return nil, err 2063 } 2064 if notification != nil { 2065 notification.MembershipStatus = ActivityCenterMembershipStatusAccepted 2066 if community.HasPermissionToSendCommunityEvents() { 2067 notification.MembershipStatus = ActivityCenterMembershipStatusAcceptedPending 2068 } 2069 notification.Read = true 2070 notification.Accepted = true 2071 notification.IncrementUpdatedAt(m.getTimesource()) 2072 2073 err = m.addActivityCenterNotification(response, notification, m.syncActivityCenterCommunityRequestDecisionAdapter) 2074 if err != nil { 2075 m.logger.Error("failed to save notification", zap.Error(err)) 2076 return nil, err 2077 } 2078 } 2079 2080 return response, nil 2081 } 2082 2083 func (m *Messenger) AcceptRequestToJoinCommunity(request *requests.AcceptRequestToJoinCommunity) (*MessengerResponse, error) { 2084 if err := request.Validate(); err != nil { 2085 return nil, err 2086 } 2087 2088 requestToJoin, err := m.communitiesManager.GetRequestToJoin(request.ID) 2089 if err != nil { 2090 return nil, err 2091 } 2092 2093 return m.acceptRequestToJoinCommunity(requestToJoin) 2094 } 2095 2096 func (m *Messenger) declineRequestToJoinCommunity(requestToJoin *communities.RequestToJoin) (*MessengerResponse, error) { 2097 community, err := m.communitiesManager.DeclineRequestToJoin(requestToJoin) 2098 if err != nil { 2099 return nil, err 2100 } 2101 2102 if community.IsControlNode() { 2103 // Notify privileged members that request to join was rejected 2104 // Send request to join without revealed addresses 2105 requestToJoin.RevealedAccounts = make([]*protobuf.RevealedAccount, 0) 2106 declinedRequestsToJoin := make(map[string]*protobuf.CommunityRequestToJoin) 2107 declinedRequestsToJoin[requestToJoin.PublicKey] = requestToJoin.ToCommunityRequestToJoinProtobuf() 2108 2109 syncMsg := &protobuf.CommunityPrivilegedUserSyncMessage{ 2110 Type: protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_REJECT_REQUEST_TO_JOIN, 2111 CommunityId: community.ID(), 2112 RequestToJoin: declinedRequestsToJoin, 2113 } 2114 2115 payloadSyncMsg, err := proto.Marshal(syncMsg) 2116 if err != nil { 2117 return nil, err 2118 } 2119 2120 rawSyncMessage := &common.RawMessage{ 2121 Payload: payloadSyncMsg, 2122 Sender: community.PrivateKey(), 2123 SkipEncryptionLayer: true, 2124 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_PRIVILEGED_USER_SYNC_MESSAGE, 2125 } 2126 2127 privilegedMembers := community.GetPrivilegedMembers() 2128 for _, privilegedMember := range privilegedMembers { 2129 if privilegedMember.Equal(&m.identity.PublicKey) { 2130 continue 2131 } 2132 _, err := m.sender.SendPrivate(context.Background(), privilegedMember, rawSyncMessage) 2133 if err != nil { 2134 return nil, err 2135 } 2136 } 2137 } 2138 2139 response := &MessengerResponse{} 2140 response.AddCommunity(community) 2141 response.AddRequestToJoinCommunity(requestToJoin) 2142 2143 // Update existing notification 2144 notification, err := m.persistence.GetActivityCenterNotificationByID(requestToJoin.ID) 2145 if err != nil { 2146 return nil, err 2147 } 2148 if notification != nil { 2149 notification.MembershipStatus = ActivityCenterMembershipStatusDeclined 2150 if community.HasPermissionToSendCommunityEvents() { 2151 notification.MembershipStatus = ActivityCenterMembershipStatusDeclinedPending 2152 } 2153 notification.Read = true 2154 notification.Dismissed = true 2155 notification.IncrementUpdatedAt(m.getTimesource()) 2156 2157 err = m.addActivityCenterNotification(response, notification, m.syncActivityCenterCommunityRequestDecisionAdapter) 2158 if err != nil { 2159 m.logger.Error("failed to save notification", zap.Error(err)) 2160 return nil, err 2161 } 2162 } 2163 2164 return response, nil 2165 } 2166 2167 func (m *Messenger) DeclineRequestToJoinCommunity(request *requests.DeclineRequestToJoinCommunity) (*MessengerResponse, error) { 2168 if err := request.Validate(); err != nil { 2169 return nil, err 2170 } 2171 2172 requestToJoin, err := m.communitiesManager.GetRequestToJoin(request.ID) 2173 if err != nil { 2174 return nil, err 2175 } 2176 2177 return m.declineRequestToJoinCommunity(requestToJoin) 2178 } 2179 2180 func (m *Messenger) LeaveCommunity(communityID types.HexBytes) (*MessengerResponse, error) { 2181 _, err := m.persistence.DismissAllActivityCenterNotificationsFromCommunity(communityID.String(), m.GetCurrentTimeInMillis()) 2182 if err != nil { 2183 return nil, err 2184 } 2185 2186 mr, err := m.leaveCommunity(communityID) 2187 if err != nil { 2188 return nil, err 2189 } 2190 2191 community, ok := mr.communities[communityID.String()] 2192 if !ok { 2193 return nil, communities.ErrOrgNotFound 2194 } 2195 2196 err = m.communitiesManager.DeleteCommunitySettings(communityID) 2197 if err != nil { 2198 return nil, err 2199 } 2200 2201 m.archiveManager.StopHistoryArchiveTasksInterval(communityID) 2202 2203 err = m.syncCommunity(context.Background(), community, m.dispatchMessage) 2204 if err != nil { 2205 return nil, err 2206 } 2207 2208 if !community.IsControlNode() { 2209 requestToLeaveProto := &protobuf.CommunityRequestToLeave{ 2210 Clock: uint64(time.Now().Unix()), 2211 CommunityId: communityID, 2212 } 2213 2214 payload, err := proto.Marshal(requestToLeaveProto) 2215 if err != nil { 2216 return nil, err 2217 } 2218 2219 community, err := m.communitiesManager.GetByID(communityID) 2220 if err != nil { 2221 return nil, err 2222 } 2223 2224 rawMessage := common.RawMessage{ 2225 Payload: payload, 2226 CommunityID: communityID, 2227 SkipEncryptionLayer: true, 2228 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_LEAVE, 2229 PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in the community pubsub topic 2230 ResendType: common.ResendTypeRawMessage, 2231 Priority: &common.HighPriority, 2232 } 2233 2234 _, err = m.SendMessageToControlNode(community, &rawMessage) 2235 if err != nil { 2236 return nil, err 2237 } 2238 2239 if _, err = m.AddRawMessageToWatch(&rawMessage); err != nil { 2240 return nil, err 2241 } 2242 } 2243 2244 return mr, nil 2245 } 2246 2247 func (m *Messenger) leaveCommunity(communityID types.HexBytes) (*MessengerResponse, error) { 2248 response := &MessengerResponse{} 2249 2250 community, err := m.communitiesManager.LeaveCommunity(communityID) 2251 if err != nil { 2252 return nil, err 2253 } 2254 2255 // Make chat inactive 2256 for chatID := range community.Chats() { 2257 communityChatID := communityID.String() + chatID 2258 response.AddRemovedChat(communityChatID) 2259 2260 _, err = m.deactivateChat(communityChatID, 0, false, false) 2261 if err != nil { 2262 return nil, err 2263 } 2264 _, err = m.transport.RemoveFilterByChatID(communityChatID) 2265 if err != nil { 2266 return nil, err 2267 } 2268 } 2269 2270 err = m.DeleteProfileShowcaseCommunity(community) 2271 if err != nil { 2272 return nil, err 2273 } 2274 2275 _, err = m.transport.RemoveFilterByChatID(communityID.String()) 2276 if err != nil { 2277 return nil, err 2278 } 2279 2280 response.AddCommunity(community) 2281 return response, nil 2282 } 2283 2284 func (m *Messenger) kickedOutOfCommunity(communityID types.HexBytes, spectateMode bool) (*MessengerResponse, error) { 2285 response := &MessengerResponse{} 2286 2287 community, err := m.communitiesManager.KickedOutOfCommunity(communityID, spectateMode) 2288 if err != nil { 2289 return nil, err 2290 } 2291 2292 if !spectateMode { 2293 err = m.DeleteProfileShowcaseCommunity(community) 2294 if err != nil { 2295 return nil, err 2296 } 2297 } 2298 2299 response.AddCommunity(community) 2300 return response, nil 2301 } 2302 2303 func (m *Messenger) CheckAndDeletePendingRequestToJoinCommunity(ctx context.Context, sendResponse bool) (*MessengerResponse, error) { 2304 sendSignal := false 2305 2306 pendingRequestsToJoin, err := m.communitiesManager.PendingRequestsToJoin() 2307 if err != nil { 2308 m.logger.Error("failed to fetch pending request to join", zap.Error(err)) 2309 return nil, err 2310 } 2311 2312 if len(pendingRequestsToJoin) == 0 { 2313 return nil, nil 2314 } 2315 2316 response := &MessengerResponse{} 2317 timeNow := uint64(time.Now().Unix()) 2318 2319 for _, requestToJoin := range pendingRequestsToJoin { 2320 requestTimeOutClock, err := communities.AddTimeoutToRequestToJoinClock(requestToJoin.Clock) 2321 if err != nil { 2322 return nil, err 2323 } 2324 2325 if timeNow >= requestTimeOutClock { 2326 err := m.communitiesManager.DeletePendingRequestToJoin(requestToJoin) 2327 if err != nil { 2328 m.logger.Error("failed to delete pending request to join", zap.String("req-id", requestToJoin.ID.String()), zap.Error(err)) 2329 return nil, err 2330 } 2331 2332 requestToJoin.Deleted = true 2333 response.AddRequestToJoinCommunity(requestToJoin) 2334 2335 notification, err := m.persistence.GetActivityCenterNotificationByID(requestToJoin.ID) 2336 if err != nil { 2337 m.logger.Error("failed to fetch pending request to join", zap.Error(err)) 2338 return nil, err 2339 } 2340 2341 if notification != nil { 2342 // Delete activity centre notification for community admin 2343 if notification.Type == ActivityCenterNotificationTypeCommunityMembershipRequest { 2344 response2, err := m.MarkActivityCenterNotificationsDeleted(ctx, []types.HexBytes{notification.ID}, m.GetCurrentTimeInMillis(), true) 2345 if err != nil { 2346 m.logger.Error("[CheckAndDeletePendingRequestToJoinCommunity] failed to mark notification as deleted", zap.Error(err)) 2347 return nil, err 2348 } 2349 response.AddActivityCenterNotifications(response2.ActivityCenterNotifications()) 2350 response.SetActivityCenterState(response2.ActivityCenterState()) 2351 } 2352 // Update activity centre notification for requester 2353 if notification.Type == ActivityCenterNotificationTypeCommunityRequest { 2354 notification.MembershipStatus = ActivityCenterMembershipStatusIdle 2355 notification.Read = false 2356 notification.Deleted = false 2357 notification.IncrementUpdatedAt(m.getTimesource()) 2358 err = m.addActivityCenterNotification(response, notification, m.syncActivityCenterUnreadByIDs) 2359 if err != nil { 2360 m.logger.Error("failed to update notification in activity center", zap.Error(err)) 2361 return nil, err 2362 } 2363 } 2364 } 2365 2366 sendSignal = true 2367 } 2368 } 2369 2370 if sendSignal && !sendResponse { 2371 signal.SendNewMessages(response) 2372 } 2373 2374 if sendResponse { 2375 return response, nil 2376 } 2377 2378 return nil, nil 2379 } 2380 2381 func (m *Messenger) CreateCommunityChat(communityID types.HexBytes, c *protobuf.CommunityChat) (*MessengerResponse, error) { 2382 var response MessengerResponse 2383 2384 c.Identity.FirstMessageTimestamp = FirstMessageTimestampNoMessage 2385 changes, err := m.communitiesManager.CreateChat(communityID, c, true, "") 2386 if err != nil { 2387 return nil, err 2388 } 2389 response.AddCommunity(changes.Community) 2390 response.CommunityChanges = []*communities.CommunityChanges{changes} 2391 2392 var chats []*Chat 2393 var publicFiltersToInit []transport.FiltersToInitialize 2394 for chatID, chat := range changes.ChatsAdded { 2395 c := CreateCommunityChat(changes.Community.IDString(), chatID, chat, m.getTimesource()) 2396 chats = append(chats, c) 2397 publicFiltersToInit = append(publicFiltersToInit, transport.FiltersToInitialize{ChatID: c.ID, PubsubTopic: changes.Community.PubsubTopic()}) 2398 2399 response.AddChat(c) 2400 } 2401 2402 // Load filters 2403 filters, err := m.transport.InitPublicFilters(publicFiltersToInit) 2404 if err != nil { 2405 return nil, err 2406 } 2407 _, err = m.scheduleSyncFilters(filters) 2408 if err != nil { 2409 return nil, err 2410 } 2411 2412 err = m.saveChats(chats) 2413 if err != nil { 2414 return nil, err 2415 } 2416 2417 err = m.reregisterForPushNotifications() 2418 if err != nil { 2419 return nil, err 2420 } 2421 2422 return &response, nil 2423 } 2424 2425 func (m *Messenger) EditCommunityChat(communityID types.HexBytes, chatID string, c *protobuf.CommunityChat) (*MessengerResponse, error) { 2426 var response MessengerResponse 2427 community, changes, err := m.communitiesManager.EditChat(communityID, chatID, c) 2428 if err != nil { 2429 return nil, err 2430 } 2431 response.AddCommunity(community) 2432 response.CommunityChanges = []*communities.CommunityChanges{changes} 2433 2434 var chats []*Chat 2435 var publicFiltersToInit []transport.FiltersToInitialize 2436 for chatID, change := range changes.ChatsModified { 2437 c := CreateCommunityChat(community.IDString(), chatID, change.ChatModified, m.getTimesource()) 2438 chats = append(chats, c) 2439 publicFiltersToInit = append(publicFiltersToInit, transport.FiltersToInitialize{ChatID: c.ID, PubsubTopic: community.PubsubTopic()}) 2440 response.AddChat(c) 2441 } 2442 2443 // Load filters 2444 filters, err := m.transport.InitPublicFilters(publicFiltersToInit) 2445 if err != nil { 2446 return nil, err 2447 } 2448 _, err = m.scheduleSyncFilters(filters) 2449 if err != nil { 2450 return nil, err 2451 } 2452 2453 return &response, m.saveChats(chats) 2454 } 2455 2456 func (m *Messenger) DeleteCommunityChat(communityID types.HexBytes, chatID string) (*MessengerResponse, error) { 2457 response := &MessengerResponse{} 2458 2459 community, _, err := m.communitiesManager.DeleteChat(communityID, chatID) 2460 if err != nil { 2461 return nil, err 2462 } 2463 err = m.deleteChat(chatID) 2464 if err != nil { 2465 return nil, err 2466 } 2467 response.AddRemovedChat(chatID) 2468 2469 _, err = m.transport.RemoveFilterByChatID(chatID) 2470 if err != nil { 2471 return nil, err 2472 } 2473 2474 response.AddCommunity(community) 2475 return response, nil 2476 } 2477 2478 func (m *Messenger) InitCommunityFilters(communityFiltersToInitialize []transport.CommunityFilterToInitialize) ([]*transport.Filter, error) { 2479 return m.transport.InitCommunityFilters(communityFiltersToInitialize) 2480 } 2481 2482 func (m *Messenger) DefaultFilters(o *communities.Community) []transport.FiltersToInitialize { 2483 cID := o.IDString() 2484 uncompressedPubKey := common.PubkeyToHex(o.PublicKey())[2:] 2485 updatesChannelID := o.StatusUpdatesChannelID() 2486 mlChannelID := o.MagnetlinkMessageChannelID() 2487 memberUpdateChannelID := o.MemberUpdateChannelID() 2488 2489 communityPubsubTopic := o.PubsubTopic() 2490 2491 filters := []transport.FiltersToInitialize{ 2492 {ChatID: cID, PubsubTopic: communityPubsubTopic}, 2493 {ChatID: updatesChannelID, PubsubTopic: communityPubsubTopic}, 2494 {ChatID: mlChannelID, PubsubTopic: communityPubsubTopic}, 2495 {ChatID: memberUpdateChannelID, PubsubTopic: communityPubsubTopic}, 2496 {ChatID: uncompressedPubKey, PubsubTopic: shard.DefaultNonProtectedPubsubTopic()}, 2497 } 2498 2499 return filters 2500 } 2501 2502 func (m *Messenger) CreateCommunity(request *requests.CreateCommunity, createDefaultChannel bool) (*MessengerResponse, error) { 2503 if err := request.Validate(); err != nil { 2504 return nil, err 2505 } 2506 2507 response := &MessengerResponse{} 2508 2509 community, err := m.communitiesManager.CreateCommunity(request, true) 2510 if err != nil { 2511 return nil, err 2512 } 2513 2514 communitySettings := communities.CommunitySettings{ 2515 CommunityID: community.IDString(), 2516 HistoryArchiveSupportEnabled: request.HistoryArchiveSupportEnabled, 2517 } 2518 err = m.communitiesManager.SaveCommunitySettings(communitySettings) 2519 if err != nil { 2520 return nil, err 2521 } 2522 2523 if err = m.subscribeToCommunityShard(community.ID(), community.Shard()); err != nil { 2524 return nil, err 2525 } 2526 2527 // Init the community filter so we can receive messages on the community 2528 _, err = m.InitCommunityFilters([]transport.CommunityFilterToInitialize{{ 2529 Shard: community.Shard(), 2530 PrivKey: community.PrivateKey(), 2531 }}) 2532 if err != nil { 2533 return nil, err 2534 } 2535 2536 // Init the default community filters 2537 _, err = m.transport.InitPublicFilters(m.DefaultFilters(community)) 2538 if err != nil { 2539 return nil, err 2540 } 2541 2542 if createDefaultChannel { 2543 chatResponse, err := m.CreateCommunityChat(community.ID(), &protobuf.CommunityChat{ 2544 Identity: &protobuf.ChatIdentity{ 2545 DisplayName: "general", 2546 Description: "General channel for the community", 2547 Color: community.Description().Identity.Color, 2548 FirstMessageTimestamp: FirstMessageTimestampNoMessage, 2549 }, 2550 Permissions: &protobuf.CommunityPermissions{ 2551 Access: protobuf.CommunityPermissions_AUTO_ACCEPT, 2552 }, 2553 }) 2554 if err != nil { 2555 return nil, err 2556 } 2557 2558 // updating community so it contains the general chat 2559 community = chatResponse.Communities()[0] 2560 response.AddChat(chatResponse.Chats()[0]) 2561 } 2562 2563 response.AddCommunity(community) 2564 response.AddCommunitySettings(&communitySettings) 2565 err = m.syncCommunity(context.Background(), community, m.dispatchMessage) 2566 if err != nil { 2567 return nil, err 2568 } 2569 2570 if m.config.torrentConfig != nil && m.config.torrentConfig.Enabled && communitySettings.HistoryArchiveSupportEnabled { 2571 go m.archiveManager.StartHistoryArchiveTasksInterval(community, messageArchiveInterval) 2572 } 2573 2574 return response, nil 2575 } 2576 2577 func (m *Messenger) SetCommunityShard(request *requests.SetCommunityShard) (*MessengerResponse, error) { 2578 if err := request.Validate(); err != nil { 2579 return nil, err 2580 } 2581 2582 community, err := m.communitiesManager.GetByID(request.CommunityID) 2583 if err != nil { 2584 return nil, err 2585 } 2586 2587 if !community.IsControlNode() { 2588 return nil, errors.New(ErrNotAdminOrOwner) 2589 } 2590 2591 // Reset the community private key 2592 community.SetPubsubTopicPrivateKey(nil) 2593 2594 // Removing the private key (if it exist) 2595 err = m.RemovePubsubTopicPrivateKey(community.PubsubTopic()) 2596 if err != nil { 2597 return nil, err 2598 } 2599 2600 // Unsubscribing from existing shard 2601 if community.Shard() != nil { 2602 err := m.unsubscribeFromShard(community.Shard()) 2603 if err != nil { 2604 return nil, err 2605 } 2606 } 2607 2608 community, err = m.communitiesManager.SetShard(request.CommunityID, request.Shard) 2609 if err != nil { 2610 return nil, err 2611 } 2612 2613 if request.Shard != nil { 2614 var topicPrivKey *ecdsa.PrivateKey 2615 if request.PrivateKey != nil { 2616 topicPrivKey, err = crypto.ToECDSA(*request.PrivateKey) 2617 } else { 2618 topicPrivKey, err = crypto.GenerateKey() 2619 } 2620 if err != nil { 2621 return nil, err 2622 } 2623 2624 community.SetPubsubTopicPrivateKey(topicPrivKey) 2625 2626 err = m.communitiesManager.UpdatePubsubTopicPrivateKey(community.PubsubTopic(), topicPrivKey) 2627 if err != nil { 2628 return nil, err 2629 } 2630 } 2631 2632 // TODO: Check 2633 err = m.UpdateCommunityFilters(community) 2634 if err != nil { 2635 return nil, err 2636 } 2637 2638 err = m.SendCommunityShardKey(community, community.GetMemberPubkeys()) 2639 if err != nil { 2640 return nil, err 2641 } 2642 2643 err = m.sendPublicCommunityShardInfo(community) 2644 if err != nil { 2645 return nil, err 2646 } 2647 2648 response := &MessengerResponse{} 2649 response.AddCommunity(community) 2650 2651 return response, nil 2652 } 2653 2654 func (m *Messenger) RemovePubsubTopicPrivateKey(topic string) error { 2655 return m.transport.RemovePubsubTopicKey(topic) 2656 } 2657 2658 func (m *Messenger) SetCommunityStorenodes(request *requests.SetCommunityStorenodes) (*MessengerResponse, error) { 2659 if err := request.Validate(); err != nil { 2660 return nil, err 2661 } 2662 community, err := m.communitiesManager.GetByID(request.CommunityID) 2663 if err != nil { 2664 return nil, err 2665 } 2666 if !community.IsControlNode() { 2667 return nil, errors.New(ErrNotAdminOrOwner) 2668 } 2669 2670 if err := m.communityStorenodes.UpdateStorenodesInDB(request.CommunityID, request.Storenodes, 0); err != nil { 2671 return nil, err 2672 } 2673 err = m.sendCommunityPublicStorenodesInfo(community, request.Storenodes) 2674 if err != nil { 2675 return nil, err 2676 } 2677 response := &MessengerResponse{ 2678 CommunityStorenodes: request.Storenodes, 2679 } 2680 return response, nil 2681 } 2682 2683 func (m *Messenger) GetCommunityStorenodes(communityID types.HexBytes) (*MessengerResponse, error) { 2684 community, err := m.communitiesManager.GetByID(communityID) 2685 if err != nil { 2686 return nil, err 2687 } 2688 if community == nil { 2689 return nil, communities.ErrOrgNotFound 2690 } 2691 2692 snodes, err := m.communityStorenodes.GetStorenodesFromDB(communityID) 2693 if err != nil { 2694 return nil, err 2695 } 2696 2697 response := &MessengerResponse{ 2698 CommunityStorenodes: snodes, 2699 } 2700 return response, nil 2701 } 2702 2703 func (m *Messenger) UpdateCommunityFilters(community *communities.Community) error { 2704 defaultFilters := m.DefaultFilters(community) 2705 publicFiltersToInit := make([]transport.FiltersToInitialize, 0, len(defaultFilters)+len(community.Chats())) 2706 2707 publicFiltersToInit = append(publicFiltersToInit, defaultFilters...) 2708 2709 for chatID := range community.Chats() { 2710 communityChatID := community.IDString() + chatID 2711 _, err := m.transport.RemoveFilterByChatID(communityChatID) 2712 if err != nil { 2713 return err 2714 } 2715 publicFiltersToInit = append(publicFiltersToInit, transport.FiltersToInitialize{ChatID: communityChatID, PubsubTopic: community.PubsubTopic()}) 2716 } 2717 2718 _, err := m.transport.InitPublicFilters(publicFiltersToInit) 2719 if err != nil { 2720 return err 2721 } 2722 2723 // Init the community filter so we can receive messages on the community 2724 _, err = m.InitCommunityFilters([]transport.CommunityFilterToInitialize{{ 2725 Shard: community.Shard(), 2726 PrivKey: community.PrivateKey(), 2727 }}) 2728 if err != nil { 2729 return err 2730 } 2731 2732 // Init the default community filters 2733 _, err = m.transport.InitPublicFilters(publicFiltersToInit) 2734 if err != nil { 2735 return err 2736 } 2737 2738 if err = m.subscribeToCommunityShard(community.ID(), community.Shard()); err != nil { 2739 return err 2740 } 2741 2742 return nil 2743 } 2744 2745 func (m *Messenger) CreateCommunityTokenPermission(request *requests.CreateCommunityTokenPermission) (*MessengerResponse, error) { 2746 request.FillDeprecatedAmount() 2747 2748 if err := request.Validate(); err != nil { 2749 return nil, err 2750 } 2751 2752 community, changes, err := m.communitiesManager.CreateCommunityTokenPermission(request) 2753 if err != nil { 2754 return nil, err 2755 } 2756 2757 if community.IsControlNode() { 2758 err = m.communitiesManager.ScheduleMembersReevaluation(community.ID()) 2759 if err != nil { 2760 return nil, err 2761 } 2762 } 2763 2764 // ensure HRkeys are synced 2765 err = m.syncCommunity(context.Background(), community, m.dispatchMessage) 2766 if err != nil { 2767 return nil, err 2768 } 2769 2770 response := &MessengerResponse{} 2771 response.AddCommunity(community) 2772 response.CommunityChanges = []*communities.CommunityChanges{changes} 2773 2774 return response, nil 2775 } 2776 2777 func (m *Messenger) EditCommunityTokenPermission(request *requests.EditCommunityTokenPermission) (*MessengerResponse, error) { 2778 request.FillDeprecatedAmount() 2779 2780 if err := request.Validate(); err != nil { 2781 return nil, err 2782 } 2783 2784 community, changes, err := m.communitiesManager.EditCommunityTokenPermission(request) 2785 if err != nil { 2786 return nil, err 2787 } 2788 2789 // check if members still fulfill the token criteria of all 2790 // BECOME_MEMBER permissions and kick them if necessary 2791 // 2792 // We do this in a separate routine to not block this function 2793 if community.IsControlNode() { 2794 err = m.communitiesManager.ScheduleMembersReevaluation(community.ID()) 2795 if err != nil { 2796 return nil, err 2797 } 2798 } 2799 2800 response := &MessengerResponse{} 2801 response.AddCommunity(community) 2802 response.CommunityChanges = []*communities.CommunityChanges{changes} 2803 2804 return response, nil 2805 } 2806 2807 func (m *Messenger) DeleteCommunityTokenPermission(request *requests.DeleteCommunityTokenPermission) (*MessengerResponse, error) { 2808 if err := request.Validate(); err != nil { 2809 return nil, err 2810 } 2811 2812 community, changes, err := m.communitiesManager.DeleteCommunityTokenPermission(request) 2813 if err != nil { 2814 return nil, err 2815 } 2816 2817 // check if members still fulfill the token criteria 2818 // We do this in a separate routine to not block this function 2819 if community.IsControlNode() { 2820 err = m.communitiesManager.ScheduleMembersReevaluation(community.ID()) 2821 if err != nil { 2822 return nil, err 2823 } 2824 } 2825 2826 response := &MessengerResponse{} 2827 response.AddCommunity(community) 2828 response.CommunityChanges = []*communities.CommunityChanges{changes} 2829 2830 return response, nil 2831 } 2832 2833 func (m *Messenger) HandleCommunityReevaluatePermissionsRequest(state *ReceivedMessageState, request *protobuf.CommunityReevaluatePermissionsRequest, statusMessage *v1protocol.StatusMessage) error { 2834 community, err := m.communitiesManager.GetByID(request.CommunityId) 2835 if err != nil { 2836 return err 2837 } 2838 2839 if !community.IsControlNode() { 2840 return communities.ErrNotControlNode 2841 } 2842 2843 if !community.IsMemberTokenMaster(statusMessage.SigPubKey()) { 2844 return communities.ErrNotAuthorized 2845 } 2846 2847 return m.communitiesManager.ScheduleMembersReevaluation(request.CommunityId) 2848 } 2849 2850 func (m *Messenger) ReevaluateCommunityMembersPermissions(request *requests.ReevaluateCommunityMembersPermissions) (*MessengerResponse, error) { 2851 if err := request.Validate(); err != nil { 2852 return nil, err 2853 } 2854 2855 community, err := m.communitiesManager.GetByID(request.CommunityID) 2856 if err != nil { 2857 return nil, err 2858 } 2859 2860 if community.IsControlNode() { 2861 err = m.communitiesManager.ScheduleMembersReevaluation(request.CommunityID) 2862 if err != nil { 2863 return nil, err 2864 } 2865 } else if community.IsTokenMaster() { 2866 reevaluateRequest := &protobuf.CommunityReevaluatePermissionsRequest{ 2867 CommunityId: request.CommunityID, 2868 } 2869 2870 encodedMessage, err := proto.Marshal(reevaluateRequest) 2871 if err != nil { 2872 return nil, err 2873 } 2874 2875 rawMessage := common.RawMessage{ 2876 Payload: encodedMessage, 2877 CommunityID: request.CommunityID, 2878 SkipEncryptionLayer: true, 2879 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST, 2880 PubsubTopic: community.PubsubTopic(), 2881 } 2882 _, err = m.SendMessageToControlNode(community, &rawMessage) 2883 if err != nil { 2884 return nil, err 2885 } 2886 } else { 2887 return nil, communities.ErrNotAuthorized 2888 } 2889 2890 return &MessengerResponse{}, nil 2891 } 2892 2893 func (m *Messenger) EditCommunity(request *requests.EditCommunity) (*MessengerResponse, error) { 2894 if err := request.Validate(); err != nil { 2895 return nil, err 2896 } 2897 2898 community, err := m.communitiesManager.EditCommunity(request) 2899 if err != nil { 2900 return nil, err 2901 } 2902 2903 communitySettings := communities.CommunitySettings{ 2904 CommunityID: community.IDString(), 2905 HistoryArchiveSupportEnabled: request.HistoryArchiveSupportEnabled, 2906 } 2907 err = m.communitiesManager.UpdateCommunitySettings(communitySettings) 2908 if err != nil { 2909 return nil, err 2910 } 2911 2912 id := community.ID() 2913 2914 if m.archiveManager.IsReady() { 2915 if !communitySettings.HistoryArchiveSupportEnabled { 2916 m.archiveManager.StopHistoryArchiveTasksInterval(id) 2917 } else if !m.archiveManager.IsSeedingHistoryArchiveTorrent(id) { 2918 var communities []*communities.Community 2919 communities = append(communities, community) 2920 go m.InitHistoryArchiveTasks(communities) 2921 } 2922 } 2923 2924 response := &MessengerResponse{} 2925 response.AddCommunity(community) 2926 response.AddCommunitySettings(&communitySettings) 2927 err = m.SyncCommunitySettings(context.Background(), &communitySettings) 2928 if err != nil { 2929 return nil, err 2930 } 2931 2932 return response, nil 2933 } 2934 2935 func (m *Messenger) RemovePrivateKey(id types.HexBytes) (*MessengerResponse, error) { 2936 community, err := m.communitiesManager.RemovePrivateKey(id) 2937 if err != nil { 2938 return nil, err 2939 } 2940 2941 response := &MessengerResponse{} 2942 response.AddCommunity(community) 2943 2944 return response, nil 2945 } 2946 2947 func (m *Messenger) ExportCommunity(id types.HexBytes) (*ecdsa.PrivateKey, error) { 2948 return m.communitiesManager.ExportCommunity(id) 2949 } 2950 2951 func (m *Messenger) ImportCommunity(ctx context.Context, key *ecdsa.PrivateKey) (*MessengerResponse, error) { 2952 clock, _ := m.getLastClockWithRelatedChat() 2953 2954 community, err := m.communitiesManager.ImportCommunity(key, clock) 2955 if err != nil { 2956 return nil, err 2957 } 2958 2959 // Load filters 2960 _, err = m.transport.InitPublicFilters(m.DefaultFilters(community)) 2961 if err != nil { 2962 return nil, err 2963 } 2964 2965 if err != nil { 2966 return nil, err 2967 } 2968 2969 _, err = m.FetchCommunity(&FetchCommunityRequest{ 2970 CommunityKey: community.IDString(), 2971 Shard: community.Shard(), 2972 TryDatabase: false, 2973 WaitForResponse: true, 2974 }) 2975 if err != nil { 2976 // TODO In the future we should add a mechanism to re-apply next steps (adding owner, joining) 2977 // if there is no connection with mailserver. Otherwise changes will be overwritten. 2978 // Do not return error to make tests pass. 2979 m.logger.Error("Can't request community info from mailserver") 2980 } 2981 2982 // We add ourselves 2983 community, err = m.communitiesManager.AddMemberOwnerToCommunity(community.ID(), &m.identity.PublicKey) 2984 if err != nil { 2985 return nil, err 2986 } 2987 2988 response, err := m.JoinCommunity(ctx, community.ID(), true) 2989 if err != nil { 2990 return nil, err 2991 } 2992 2993 // Notify other clients we are the control node now 2994 err = m.syncCommunity(context.Background(), community, m.dispatchMessage) 2995 if err != nil { 2996 return nil, err 2997 } 2998 2999 if m.archiveManager.IsReady() { 3000 var communities []*communities.Community 3001 communities = append(communities, community) 3002 go m.InitHistoryArchiveTasks(communities) 3003 } 3004 return response, nil 3005 } 3006 3007 func (m *Messenger) GetCommunityByID(communityID types.HexBytes) (*communities.Community, error) { 3008 return m.communitiesManager.GetByID(communityID) 3009 } 3010 3011 func (m *Messenger) ShareCommunity(request *requests.ShareCommunity) (*MessengerResponse, error) { 3012 if err := request.Validate(); err != nil { 3013 return nil, err 3014 } 3015 community, err := m.GetCommunityByID(request.CommunityID) 3016 if err != nil { 3017 return nil, err 3018 } 3019 3020 response := &MessengerResponse{} 3021 communityURL, err := m.ShareCommunityURLWithData(request.CommunityID) 3022 if err != nil { 3023 return nil, err 3024 } 3025 3026 var statusLinkPreview common.StatusLinkPreview 3027 statusCommunityLinkPreview, err := community.ToStatusLinkPreview() 3028 if err != nil { 3029 return nil, err 3030 } 3031 3032 statusLinkPreview.URL = communityURL 3033 statusLinkPreview.Community = statusCommunityLinkPreview 3034 var messages []*common.Message 3035 for _, pk := range request.Users { 3036 message := common.NewMessage() 3037 message.StatusLinkPreviews = []common.StatusLinkPreview{statusLinkPreview} 3038 message.ChatId = pk.String() 3039 message.Shard = community.Shard().Protobuffer() 3040 message.ContentType = protobuf.ChatMessage_TEXT_PLAIN 3041 message.Text = communityURL 3042 if request.InviteMessage != "" { 3043 message.Text = fmt.Sprintf("%s\n%s", request.InviteMessage, communityURL) 3044 } 3045 messages = append(messages, message) 3046 r, err := m.CreateOneToOneChat(&requests.CreateOneToOneChat{ID: pk}) 3047 if err != nil { 3048 return nil, err 3049 } 3050 3051 if err := response.Merge(r); err != nil { 3052 return nil, err 3053 } 3054 } 3055 3056 sendMessagesResponse, err := m.SendChatMessages(context.Background(), messages) 3057 if err != nil { 3058 return nil, err 3059 } 3060 3061 if err := response.Merge(sendMessagesResponse); err != nil { 3062 return nil, err 3063 } 3064 3065 return response, nil 3066 } 3067 3068 func (m *Messenger) MyCanceledRequestsToJoin() ([]*communities.RequestToJoin, error) { 3069 return m.communitiesManager.CanceledRequestsToJoinForUser(&m.identity.PublicKey) 3070 } 3071 3072 func (m *Messenger) MyPendingRequestsToJoin() ([]*communities.RequestToJoin, error) { 3073 return m.communitiesManager.PendingRequestsToJoinForUser(&m.identity.PublicKey) 3074 } 3075 3076 func (m *Messenger) LatestRequestToJoinForCommunity(communityID types.HexBytes) (*communities.RequestToJoin, error) { 3077 return m.communitiesManager.GetCommunityRequestToJoinWithRevealedAddresses(m.myHexIdentity(), communityID) 3078 } 3079 3080 func (m *Messenger) PendingRequestsToJoinForCommunity(id types.HexBytes) ([]*communities.RequestToJoin, error) { 3081 return m.communitiesManager.PendingRequestsToJoinForCommunity(id) 3082 } 3083 3084 func (m *Messenger) DeclinedRequestsToJoinForCommunity(id types.HexBytes) ([]*communities.RequestToJoin, error) { 3085 return m.communitiesManager.DeclinedRequestsToJoinForCommunity(id) 3086 } 3087 3088 func (m *Messenger) CanceledRequestsToJoinForCommunity(id types.HexBytes) ([]*communities.RequestToJoin, error) { 3089 return m.communitiesManager.CanceledRequestsToJoinForCommunity(id) 3090 } 3091 3092 func (m *Messenger) AcceptedRequestsToJoinForCommunity(id types.HexBytes) ([]*communities.RequestToJoin, error) { 3093 return m.communitiesManager.AcceptedRequestsToJoinForCommunity(id) 3094 } 3095 3096 func (m *Messenger) AcceptedPendingRequestsToJoinForCommunity(id types.HexBytes) ([]*communities.RequestToJoin, error) { 3097 return m.communitiesManager.AcceptedPendingRequestsToJoinForCommunity(id) 3098 } 3099 3100 func (m *Messenger) DeclinedPendingRequestsToJoinForCommunity(id types.HexBytes) ([]*communities.RequestToJoin, error) { 3101 return m.communitiesManager.DeclinedPendingRequestsToJoinForCommunity(id) 3102 } 3103 3104 func (m *Messenger) AllNonApprovedCommunitiesRequestsToJoin() ([]*communities.RequestToJoin, error) { 3105 return m.communitiesManager.AllNonApprovedCommunitiesRequestsToJoin() 3106 } 3107 3108 func (m *Messenger) RemoveUserFromCommunity(id types.HexBytes, pkString string) (*MessengerResponse, error) { 3109 publicKey, err := common.HexToPubkey(pkString) 3110 if err != nil { 3111 return nil, err 3112 } 3113 3114 community, err := m.communitiesManager.RemoveUserFromCommunity(id, publicKey) 3115 if err != nil { 3116 return nil, err 3117 } 3118 3119 response := &MessengerResponse{} 3120 response.AddCommunity(community) 3121 return response, nil 3122 } 3123 3124 func (m *Messenger) SendCommunityShardKey(community *communities.Community, pubkeys []*ecdsa.PublicKey) error { 3125 if m.transport.WakuVersion() != 2 { 3126 return nil 3127 } 3128 3129 if !community.IsControlNode() { 3130 return nil 3131 } 3132 3133 keyBytes := make([]byte, 0) 3134 key := community.PubsubTopicPrivateKey() 3135 if key != nil { 3136 keyBytes = crypto.FromECDSA(key) 3137 } 3138 3139 communityShardKey := &protobuf.CommunityShardKey{ 3140 Clock: community.Clock(), 3141 CommunityId: community.ID(), 3142 PrivateKey: keyBytes, 3143 Shard: community.Shard().Protobuffer(), 3144 } 3145 3146 encodedMessage, err := proto.Marshal(communityShardKey) 3147 if err != nil { 3148 return err 3149 } 3150 3151 rawMessage := common.RawMessage{ 3152 Recipients: pubkeys, 3153 ResendType: common.ResendTypeDataSync, 3154 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_SHARD_KEY, 3155 Payload: encodedMessage, 3156 } 3157 3158 _, err = m.sender.SendPubsubTopicKey(context.Background(), &rawMessage) 3159 3160 return err 3161 } 3162 3163 func (m *Messenger) UnbanUserFromCommunity(request *requests.UnbanUserFromCommunity) (*MessengerResponse, error) { 3164 community, err := m.communitiesManager.UnbanUserFromCommunity(request) 3165 if err != nil { 3166 return nil, err 3167 } 3168 3169 response := &MessengerResponse{} 3170 response.AddCommunity(community) 3171 return response, nil 3172 } 3173 3174 func (m *Messenger) BanUserFromCommunity(ctx context.Context, request *requests.BanUserFromCommunity) (*MessengerResponse, error) { 3175 community, err := m.communitiesManager.BanUserFromCommunity(request) 3176 if err != nil { 3177 return nil, err 3178 } 3179 3180 response := &MessengerResponse{} 3181 response, err = m.DeclineAllPendingGroupInvitesFromUser(ctx, response, request.User.String()) 3182 if err != nil { 3183 return nil, err 3184 } 3185 3186 response.AddCommunity(community) 3187 3188 if request.DeleteAllMessages && community.IsControlNode() { 3189 deleteMessagesResponse, err := m.deleteCommunityMemberMessages(request.User.String(), request.CommunityID.String(), []*protobuf.DeleteCommunityMemberMessage{}) 3190 if err != nil { 3191 return nil, err 3192 } 3193 3194 err = response.Merge(deleteMessagesResponse) 3195 if err != nil { 3196 return nil, err 3197 } 3198 3199 // signal client with community and messages changes 3200 if m.config.messengerSignalsHandler != nil { 3201 m.config.messengerSignalsHandler.MessengerResponse(deleteMessagesResponse) 3202 } 3203 } 3204 3205 return response, nil 3206 } 3207 3208 func (m *Messenger) AddRoleToMember(request *requests.AddRoleToMember) (*MessengerResponse, error) { 3209 if err := request.Validate(); err != nil { 3210 return nil, err 3211 } 3212 community, err := m.communitiesManager.AddRoleToMember(request) 3213 if err != nil { 3214 return nil, err 3215 } 3216 3217 response := &MessengerResponse{} 3218 response.AddCommunity(community) 3219 return response, nil 3220 } 3221 3222 func (m *Messenger) RemoveRoleFromMember(request *requests.RemoveRoleFromMember) (*MessengerResponse, error) { 3223 if err := request.Validate(); err != nil { 3224 return nil, err 3225 } 3226 community, err := m.communitiesManager.RemoveRoleFromMember(request) 3227 if err != nil { 3228 return nil, err 3229 } 3230 3231 response := &MessengerResponse{} 3232 response.AddCommunity(community) 3233 return response, nil 3234 } 3235 3236 func (m *Messenger) FindCommunityInfoFromDB(communityID string) (*communities.Community, error) { 3237 id, err := hexutil.Decode(communityID) 3238 if err != nil { 3239 return nil, err 3240 } 3241 3242 var community *communities.Community 3243 community, err = m.GetCommunityByID(id) 3244 if err != nil { 3245 return nil, err 3246 } 3247 return community, nil 3248 } 3249 3250 // FetchCommunity installs filter for community and requests its details 3251 // from mailserver. 3252 // 3253 // If `request.TryDatabase` is true, it first looks for community in database, 3254 // and requests from mailserver only if it wasn't found locally. 3255 // If `request.WaitForResponse` is true, it waits until it has the community before returning it. 3256 // If `request.WaitForResponse` is false, it installs filter for community and requests its details 3257 // from mailserver. When response received it will be passed through signals handler. 3258 func (m *Messenger) FetchCommunity(request *FetchCommunityRequest) (*communities.Community, error) { 3259 if err := request.Validate(); err != nil { 3260 return nil, fmt.Errorf("invalid request: %w", err) 3261 } 3262 communityID := request.getCommunityID() 3263 3264 if request.TryDatabase { 3265 community, err := m.FindCommunityInfoFromDB(communityID) 3266 if err != nil && err != communities.ErrOrgNotFound { 3267 return nil, err 3268 } 3269 if community != nil { 3270 if !request.WaitForResponse { 3271 m.config.messengerSignalsHandler.CommunityInfoFound(community) 3272 } 3273 return community, nil 3274 } 3275 } 3276 3277 communityAddress := communities.CommunityShard{ 3278 CommunityID: communityID, 3279 Shard: request.Shard, 3280 } 3281 3282 options := []StoreNodeRequestOption{ 3283 WithWaitForResponseOption(request.WaitForResponse), 3284 } 3285 3286 community, _, err := m.storeNodeRequestsManager.FetchCommunity(communityAddress, options) 3287 3288 return community, err 3289 } 3290 3291 // fetchCommunities installs filter for community and requests its details from store node. 3292 // When response received it will be passed through signals handler. 3293 func (m *Messenger) fetchCommunities(communities []communities.CommunityShard) error { 3294 return m.storeNodeRequestsManager.FetchCommunities(communities, []StoreNodeRequestOption{}) 3295 } 3296 3297 // passStoredCommunityInfoToSignalHandler calls signal handler with community info 3298 func (m *Messenger) passStoredCommunityInfoToSignalHandler(community *communities.Community) { 3299 if m.config.messengerSignalsHandler == nil { 3300 return 3301 } 3302 m.config.messengerSignalsHandler.CommunityInfoFound(community) 3303 } 3304 3305 // handleCommunityDescription handles an community description 3306 func (m *Messenger) handleCommunityDescription(state *ReceivedMessageState, signer *ecdsa.PublicKey, description *protobuf.CommunityDescription, rawPayload []byte, verifiedOwner *ecdsa.PublicKey, shard *protobuf.Shard) error { 3307 communityResponse, err := m.communitiesManager.HandleCommunityDescriptionMessage(signer, description, rawPayload, verifiedOwner, shard) 3308 if err != nil { 3309 return err 3310 } 3311 3312 // If response is nil, but not error, it will be processed async 3313 if communityResponse == nil { 3314 return nil 3315 } 3316 3317 if len(communityResponse.FailedToDecrypt) != 0 { 3318 for _, r := range communityResponse.FailedToDecrypt { 3319 if state.CurrentMessageState != nil && state.CurrentMessageState.StatusMessage != nil { 3320 err := m.persistence.SaveHashRatchetMessage(r.GroupID, r.KeyID, state.CurrentMessageState.StatusMessage.TransportLayer.Message) 3321 m.logger.Info("saving failed to decrypt community description", zap.String("hash", types.Bytes2Hex(state.CurrentMessageState.StatusMessage.TransportLayer.Message.Hash))) 3322 if err != nil { 3323 m.logger.Warn("failed to save waku message") 3324 } 3325 } 3326 3327 } 3328 // We stop here if we could not decrypt the community main metadata 3329 if communityResponse.Community == nil { 3330 return nil 3331 } 3332 } 3333 3334 return m.handleCommunityResponse(state, communityResponse) 3335 } 3336 3337 func (m *Messenger) handleCommunityResponse(state *ReceivedMessageState, communityResponse *communities.CommunityResponse) error { 3338 community := communityResponse.Community 3339 3340 if len(communityResponse.Changes.MembersBanned) > 0 { 3341 for memberID, deleteAllMessages := range communityResponse.Changes.MembersBanned { 3342 if deleteAllMessages { 3343 response, err := m.deleteCommunityMemberMessages(memberID, community.IDString(), []*protobuf.DeleteCommunityMemberMessage{}) 3344 if err != nil { 3345 return err 3346 } 3347 3348 if err = state.Response.Merge(response); err != nil { 3349 return err 3350 } 3351 } 3352 } 3353 } 3354 3355 state.Response.AddCommunity(community) 3356 state.Response.CommunityChanges = append(state.Response.CommunityChanges, communityResponse.Changes) 3357 state.Response.AddRequestsToJoinCommunity(communityResponse.RequestsToJoin) 3358 3359 // If we haven't joined/spectated the org, nothing to do 3360 if !community.Joined() && !community.Spectated() { 3361 return nil 3362 } 3363 3364 removedChatIDs := make([]string, 0) 3365 for id := range communityResponse.Changes.ChatsRemoved { 3366 chatID := community.ChatID(id) 3367 _, ok := state.AllChats.Load(chatID) 3368 if ok { 3369 removedChatIDs = append(removedChatIDs, chatID) 3370 state.AllChats.Delete(chatID) 3371 err := m.DeleteChat(chatID) 3372 if err != nil { 3373 m.logger.Error("couldn't delete chat", zap.Error(err)) 3374 } 3375 } 3376 } 3377 3378 // Check if we have been removed from a chat (ie no longer have access) 3379 for channelID, changes := range communityResponse.Changes.ChatsModified { 3380 if _, ok := changes.MembersRemoved[common.PubkeyToHex(&m.identity.PublicKey)]; ok { 3381 chatID := community.ChatID(channelID) 3382 3383 if chat, ok := state.AllChats.Load(chatID); ok { 3384 // Reset the chat's message counts 3385 chat.UnviewedMessagesCount = 0 3386 chat.UnviewedMentionsCount = 0 3387 err := m.saveChat(chat) 3388 if err != nil { 3389 return err 3390 } 3391 state.Response.AddChat(chat) 3392 } 3393 } 3394 } 3395 3396 // Update relevant chats names and add new ones 3397 // Currently removal is not supported 3398 chats := CreateCommunityChats(community, state.Timesource) 3399 var publicFiltersToInit []transport.FiltersToInitialize 3400 for i, chat := range chats { 3401 3402 oldChat, ok := state.AllChats.Load(chat.ID) 3403 if !ok { 3404 // Beware, don't use the reference in the range (i.e chat) as it's a shallow copy 3405 state.AllChats.Store(chat.ID, chats[i]) 3406 3407 state.Response.AddChat(chat) 3408 publicFiltersToInit = append(publicFiltersToInit, transport.FiltersToInitialize{ 3409 ChatID: chat.ID, 3410 PubsubTopic: community.PubsubTopic(), 3411 }) 3412 // Update name, currently is the only field is mutable 3413 } else if oldChat.Name != chat.Name || 3414 oldChat.Description != chat.Description || 3415 oldChat.Emoji != chat.Emoji || 3416 oldChat.Color != chat.Color || 3417 oldChat.HideIfPermissionsNotMet != chat.HideIfPermissionsNotMet || 3418 oldChat.UpdateFirstMessageTimestamp(chat.FirstMessageTimestamp) { 3419 oldChat.Name = chat.Name 3420 oldChat.Description = chat.Description 3421 oldChat.Emoji = chat.Emoji 3422 oldChat.Color = chat.Color 3423 oldChat.HideIfPermissionsNotMet = chat.HideIfPermissionsNotMet 3424 // TODO(samyoul) remove storing of an updated reference pointer? 3425 state.AllChats.Store(chat.ID, oldChat) 3426 state.Response.AddChat(chat) 3427 } 3428 } 3429 3430 for _, chatID := range removedChatIDs { 3431 _, err := m.transport.RemoveFilterByChatID(chatID) 3432 if err != nil { 3433 m.logger.Error("couldn't remove filter", zap.Error(err)) 3434 } 3435 } 3436 3437 // Load transport filters 3438 filters, err := m.transport.InitPublicFilters(publicFiltersToInit) 3439 if err != nil { 3440 return err 3441 } 3442 _, err = m.scheduleSyncFilters(filters) 3443 if err != nil { 3444 return err 3445 } 3446 3447 for _, requestToJoin := range communityResponse.RequestsToJoin { 3448 // Activity Center notification 3449 notification, err := m.persistence.GetActivityCenterNotificationByID(requestToJoin.ID) 3450 if err != nil { 3451 return err 3452 } 3453 3454 if notification != nil { 3455 notification.MembershipStatus = ActivityCenterMembershipStatusAccepted 3456 switch requestToJoin.State { 3457 case communities.RequestToJoinStateDeclined: 3458 notification.MembershipStatus = ActivityCenterMembershipStatusDeclined 3459 case communities.RequestToJoinStateAccepted: 3460 notification.MembershipStatus = ActivityCenterMembershipStatusAccepted 3461 case communities.RequestToJoinStateAcceptedPending: 3462 notification.MembershipStatus = ActivityCenterMembershipStatusAcceptedPending 3463 case communities.RequestToJoinStateDeclinedPending: 3464 notification.MembershipStatus = ActivityCenterMembershipStatusDeclinedPending 3465 case communities.RequestToJoinStateAwaitingAddresses: 3466 notification.MembershipStatus = ActivityCenterMembershipOwnershipChanged 3467 default: 3468 notification.MembershipStatus = ActivityCenterMembershipStatusPending 3469 3470 } 3471 3472 notification.Read = true 3473 notification.Accepted = true 3474 notification.IncrementUpdatedAt(m.getTimesource()) 3475 3476 err = m.addActivityCenterNotification(state.Response, notification, nil) 3477 if err != nil { 3478 m.logger.Error("failed to save notification", zap.Error(err)) 3479 return err 3480 } 3481 } 3482 } 3483 3484 return nil 3485 } 3486 3487 func (m *Messenger) HandleCommunityUserKicked(state *ReceivedMessageState, message *protobuf.CommunityUserKicked, statusMessage *v1protocol.StatusMessage) error { 3488 // TODO: validate the user can be removed checking the signer 3489 if len(message.CommunityId) == 0 { 3490 return nil 3491 } 3492 community, err := m.communitiesManager.GetByID(message.CommunityId) 3493 if err != nil { 3494 return err 3495 } 3496 if community == nil || !community.Joined() { 3497 return nil 3498 } 3499 if community.Clock() > message.Clock { 3500 return nil 3501 } 3502 3503 response, err := m.kickedOutOfCommunity(community.ID(), false) 3504 if err != nil { 3505 m.logger.Error("cannot leave community", zap.Error(err)) 3506 return err 3507 } 3508 3509 if err := state.Response.Merge(response); err != nil { 3510 m.logger.Error("cannot merge join community response", zap.Error(err)) 3511 return err 3512 } 3513 3514 return nil 3515 } 3516 3517 func (m *Messenger) HandleCommunityEventsMessage(state *ReceivedMessageState, message *protobuf.CommunityEventsMessage, statusMessage *v1protocol.StatusMessage) error { 3518 signer := state.CurrentMessageState.PublicKey 3519 communityResponse, err := m.communitiesManager.HandleCommunityEventsMessage(signer, message) 3520 if err != nil { 3521 return err 3522 } 3523 3524 return m.handleCommunityResponse(state, communityResponse) 3525 } 3526 3527 // HandleCommunityShardKey handles the private keys for the community shards 3528 func (m *Messenger) HandleCommunityShardKey(state *ReceivedMessageState, message *protobuf.CommunityShardKey, statusMessage *v1protocol.StatusMessage) error { 3529 community, err := m.communitiesManager.GetByID(message.CommunityId) 3530 if err != nil { 3531 return err 3532 } 3533 3534 // If we haven't joined the community, nothing to do 3535 if !community.Joined() { 3536 return nil 3537 } 3538 3539 signer := state.CurrentMessageState.PublicKey 3540 if signer == nil { 3541 return errors.New(ErrReceiverIsNil) 3542 } 3543 3544 err = m.handleCommunityShardAndFiltersFromProto(community, message) 3545 if err != nil { 3546 return err 3547 } 3548 3549 state.Response.AddCommunity(community) 3550 3551 return nil 3552 } 3553 3554 func (m *Messenger) handleCommunityShardAndFiltersFromProto(community *communities.Community, message *protobuf.CommunityShardKey) error { 3555 err := m.communitiesManager.UpdateShard(community, shard.FromProtobuff(message.Shard), message.Clock) 3556 if err != nil { 3557 return err 3558 } 3559 3560 var privKey *ecdsa.PrivateKey = nil 3561 if message.Shard != nil { 3562 if message.PrivateKey != nil { 3563 privKey, err = crypto.ToECDSA(message.PrivateKey) 3564 if err != nil { 3565 return err 3566 } 3567 } 3568 } 3569 3570 // Removing the existing private key (if any) 3571 err = m.RemovePubsubTopicPrivateKey(community.PubsubTopic()) 3572 if err != nil { 3573 return err 3574 } 3575 3576 // Unsubscribing from existing shard 3577 if community.Shard() != nil && community.Shard() != shard.FromProtobuff(message.GetShard()) { 3578 err := m.unsubscribeFromShard(community.Shard()) 3579 if err != nil { 3580 return err 3581 } 3582 } 3583 3584 community.SetPubsubTopicPrivateKey(privKey) 3585 3586 err = m.communitiesManager.UpdatePubsubTopicPrivateKey(community.PubsubTopic(), privKey) 3587 if err != nil { 3588 return err 3589 } 3590 // Update community filters in case of change of shard 3591 if community.Shard() != shard.FromProtobuff(message.GetShard()) { 3592 err = m.UpdateCommunityFilters(community) 3593 if err != nil { 3594 return err 3595 } 3596 3597 } 3598 return nil 3599 } 3600 3601 func (m *Messenger) handleCommunityPrivilegedUserSyncMessage(state *ReceivedMessageState, signer *ecdsa.PublicKey, message *protobuf.CommunityPrivilegedUserSyncMessage) error { 3602 if signer == nil { 3603 return errors.New(ErrSignerIsNil) 3604 } 3605 3606 community, err := m.communitiesManager.GetByID(message.CommunityId) 3607 if err != nil { 3608 return err 3609 } 3610 3611 if community.IsControlNode() { 3612 return nil 3613 } 3614 3615 // Currently this type of msg coming from the control node. 3616 // If it will change in the future, check that events types starting from 3617 // CONTROL_NODE were sent by a control node 3618 isControlNodeMsg := common.IsPubKeyEqual(community.ControlNode(), signer) 3619 if !isControlNodeMsg { 3620 return errors.New(ErrSyncMessagesSentByNonControlNode) 3621 } 3622 3623 err = m.communitiesManager.ValidateCommunityPrivilegedUserSyncMessage(message) 3624 if err != nil { 3625 return err 3626 } 3627 3628 switch message.Type { 3629 case protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ACCEPT_REQUEST_TO_JOIN: 3630 fallthrough 3631 case protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_REJECT_REQUEST_TO_JOIN: 3632 requestsToJoin, err := m.communitiesManager.HandleRequestToJoinPrivilegedUserSyncMessage(message, community) 3633 if err != nil { 3634 return err 3635 } 3636 state.Response.AddRequestsToJoinCommunity(requestsToJoin) 3637 3638 case protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN: 3639 nonAcceptedRequestsToJoin, err := m.communitiesManager.HandleSyncAllRequestToJoinForNewPrivilegedMember(message, community) 3640 if err != nil { 3641 return err 3642 } 3643 state.Response.AddRequestsToJoinCommunity(nonAcceptedRequestsToJoin) 3644 case protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_MEMBER_EDIT_SHARED_ADDRESSES: 3645 err = m.communitiesManager.HandleEditSharedAddressesPrivilegedUserSyncMessage(message, community) 3646 if err != nil { 3647 return err 3648 } 3649 } 3650 3651 return nil 3652 } 3653 3654 func (m *Messenger) HandleCommunityPrivilegedUserSyncMessage(state *ReceivedMessageState, message *protobuf.CommunityPrivilegedUserSyncMessage, statusMessage *v1protocol.StatusMessage) error { 3655 signer := state.CurrentMessageState.PublicKey 3656 return m.handleCommunityPrivilegedUserSyncMessage(state, signer, message) 3657 } 3658 3659 func (m *Messenger) sendSharedAddressToControlNode(receiver *ecdsa.PublicKey, community *communities.Community) (*communities.RequestToJoin, error) { 3660 if receiver == nil { 3661 return nil, errors.New(ErrReceiverIsNil) 3662 } 3663 3664 if community == nil { 3665 return nil, communities.ErrOrgNotFound 3666 } 3667 3668 m.logger.Info("share address to the new owner ", zap.String("community id", community.IDString())) 3669 3670 pk := common.PubkeyToHex(&m.identity.PublicKey) 3671 3672 requestToJoin, err := m.communitiesManager.GetCommunityRequestToJoinWithRevealedAddresses(pk, community.ID()) 3673 if err != nil { 3674 if err == sql.ErrNoRows { 3675 return nil, communities.ErrRevealedAccountsAbsent 3676 } 3677 return nil, err 3678 } 3679 3680 if len(requestToJoin.RevealedAccounts) == 0 { 3681 return nil, communities.ErrRevealedAccountsAbsent 3682 } 3683 3684 // check if at least one account is signed 3685 // old community users can not keep locally the signature of their revealed accounts in the DB 3686 revealedAccountSigned := false 3687 for _, account := range requestToJoin.RevealedAccounts { 3688 revealedAccountSigned = len(account.Signature) > 0 3689 if revealedAccountSigned { 3690 break 3691 } 3692 } 3693 3694 if !revealedAccountSigned { 3695 return nil, communities.ErrNoRevealedAccountsSignature 3696 } 3697 3698 requestToJoin.Clock = uint64(time.Now().Unix()) 3699 requestToJoin.State = communities.RequestToJoinStateAwaitingAddresses 3700 payload, err := proto.Marshal(requestToJoin.ToCommunityRequestToJoinProtobuf()) 3701 if err != nil { 3702 return nil, err 3703 } 3704 3705 rawMessage := common.RawMessage{ 3706 Payload: payload, 3707 CommunityID: community.ID(), 3708 SkipEncryptionLayer: false, 3709 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN, 3710 PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic 3711 ResendType: common.ResendTypeDataSync, 3712 ResendMethod: common.ResendMethodSendPrivate, 3713 Recipients: []*ecdsa.PublicKey{receiver}, 3714 } 3715 3716 if err = m.communitiesManager.SaveRequestToJoin(requestToJoin); err != nil { 3717 return nil, err 3718 } 3719 3720 _, err = m.sender.SendPrivate(context.Background(), receiver, &rawMessage) 3721 if err != nil { 3722 return nil, err 3723 } 3724 3725 return requestToJoin, err 3726 } 3727 3728 func (m *Messenger) HandleSyncInstallationCommunity(messageState *ReceivedMessageState, syncCommunity *protobuf.SyncInstallationCommunity, statusMessage *v1protocol.StatusMessage) error { 3729 return m.handleSyncInstallationCommunity(messageState, syncCommunity) 3730 } 3731 3732 func (m *Messenger) handleSyncInstallationCommunity(messageState *ReceivedMessageState, syncCommunity *protobuf.SyncInstallationCommunity) error { 3733 logger := m.logger.Named("handleSyncInstallationCommunity") 3734 3735 // Should handle community 3736 shouldHandle, err := m.communitiesManager.ShouldHandleSyncCommunity(syncCommunity) 3737 if err != nil { 3738 logger.Debug("m.communitiesManager.ShouldHandleSyncCommunity error", zap.Error(err)) 3739 return err 3740 } 3741 logger.Debug("ShouldHandleSyncCommunity result", zap.Bool("shouldHandle", shouldHandle)) 3742 if !shouldHandle { 3743 return nil 3744 } 3745 3746 // Handle deprecated community keys 3747 if len(syncCommunity.EncryptionKeysV1) != 0 { 3748 // We pass nil,nil as private key/public key as they won't be encrypted 3749 _, err := m.encryptor.HandleHashRatchetKeysPayload(syncCommunity.Id, syncCommunity.EncryptionKeysV1, nil, nil) 3750 if err != nil { 3751 return err 3752 } 3753 } 3754 3755 // Handle community and channel keys 3756 if len(syncCommunity.EncryptionKeysV2) != 0 { 3757 err := m.encryptor.HandleHashRatchetHeadersPayload(syncCommunity.EncryptionKeysV2) 3758 if err != nil { 3759 return err 3760 } 3761 } 3762 3763 // Handle any community requests to join. 3764 // MUST BE HANDLED BEFORE DESCRIPTION! 3765 pending := false 3766 for _, rtj := range syncCommunity.RequestsToJoin { 3767 req := new(communities.RequestToJoin) 3768 req.InitFromSyncProtobuf(rtj) 3769 3770 if req.State == communities.RequestToJoinStatePending { 3771 pending = true 3772 } 3773 3774 err = m.communitiesManager.SaveRequestToJoin(req) 3775 if err != nil && err != communities.ErrOldRequestToJoin { 3776 logger.Debug("m.communitiesManager.SaveRequestToJoin error", zap.Error(err)) 3777 return err 3778 } 3779 } 3780 logger.Debug("community requests to join pending state", zap.Bool("pending", pending)) 3781 3782 // Don't use the public key of the private key, uncompress the community id 3783 orgPubKey, err := crypto.DecompressPubkey(syncCommunity.Id) 3784 if err != nil { 3785 logger.Debug("crypto.DecompressPubkey error", zap.Error(err)) 3786 return err 3787 } 3788 logger.Debug("crypto.DecompressPubkey result", zap.Any("orgPubKey", orgPubKey)) 3789 3790 var amm protobuf.ApplicationMetadataMessage 3791 err = proto.Unmarshal(syncCommunity.Description, &amm) 3792 if err != nil { 3793 logger.Debug("proto.Unmarshal protobuf.ApplicationMetadataMessage error", zap.Error(err)) 3794 return err 3795 } 3796 3797 var cd protobuf.CommunityDescription 3798 err = proto.Unmarshal(amm.Payload, &cd) 3799 if err != nil { 3800 logger.Debug("proto.Unmarshal protobuf.CommunityDescription error", zap.Error(err)) 3801 return err 3802 } 3803 3804 // This is our own message, so we can trust the set community owner 3805 // This is good to do so that we don't have to queue all the actions done after the handled community description. 3806 // `signer` is `communityID` for a community with no owner token and `owner public key` otherwise 3807 signer, err := utils.RecoverKey(&amm) 3808 if err != nil { 3809 logger.Debug("failed to recover community description signer", zap.Error(err)) 3810 return err 3811 } 3812 3813 // Passing shard as nil so that defaultProtected shard 32 is considered 3814 err = m.handleCommunityDescription(messageState, signer, &cd, syncCommunity.Description, signer, nil) 3815 // Even if the Description is outdated we should proceed in order to sync settings and joined state 3816 if err != nil && err != communities.ErrInvalidCommunityDescriptionClockOutdated { 3817 logger.Debug("m.handleCommunityDescription error", zap.Error(err)) 3818 return err 3819 } 3820 descriptionOutdated := err == communities.ErrInvalidCommunityDescriptionClockOutdated 3821 3822 if syncCommunity.Settings != nil { 3823 err = m.HandleSyncCommunitySettings(messageState, syncCommunity.Settings, nil) 3824 if err != nil { 3825 logger.Debug("m.handleSyncCommunitySettings error", zap.Error(err)) 3826 return err 3827 } 3828 } 3829 3830 if syncCommunity.ControlNode != nil { 3831 err = m.communitiesManager.SetSyncControlNode(syncCommunity.Id, syncCommunity.ControlNode) 3832 if err != nil { 3833 logger.Debug("m.SetSyncControlNode", zap.Error(err)) 3834 return err 3835 } 3836 } 3837 3838 // Handle community last updated 3839 if syncCommunity.LastOpenedAt > 0 { 3840 _, err = m.communitiesManager.CommunityUpdateLastOpenedAt(syncCommunity.Id, syncCommunity.LastOpenedAt) 3841 if err != nil { 3842 logger.Debug("m.CommunityUpdateLastOpenedAt", zap.Error(err)) 3843 return err 3844 } 3845 } 3846 3847 // if we are not waiting for approval, join or leave the community 3848 if !pending && !descriptionOutdated { 3849 var mr *MessengerResponse 3850 if syncCommunity.Joined { 3851 mr, err = m.joinCommunity(context.Background(), syncCommunity.Id, false) 3852 if err != nil && err != communities.ErrOrgAlreadyJoined { 3853 logger.Debug("m.joinCommunity error", zap.Error(err)) 3854 return err 3855 } 3856 } else { 3857 mr, err = m.leaveCommunity(syncCommunity.Id) 3858 if err != nil { 3859 logger.Debug("m.leaveCommunity error", zap.Error(err)) 3860 return err 3861 } 3862 } 3863 if mr != nil { 3864 err = messageState.Response.Merge(mr) 3865 if err != nil { 3866 logger.Debug("messageState.Response.Merge error", zap.Error(err)) 3867 return err 3868 } 3869 } 3870 } 3871 3872 // update the clock value 3873 err = m.communitiesManager.SetSyncClock(syncCommunity.Id, syncCommunity.Clock) 3874 if err != nil { 3875 logger.Debug("m.communitiesManager.SetSyncClock", zap.Error(err)) 3876 return err 3877 } 3878 3879 return nil 3880 } 3881 3882 func (m *Messenger) HandleSyncCommunitySettings(messageState *ReceivedMessageState, syncCommunitySettings *protobuf.SyncCommunitySettings, statusMessage *v1protocol.StatusMessage) error { 3883 shouldHandle, err := m.communitiesManager.ShouldHandleSyncCommunitySettings(syncCommunitySettings) 3884 if err != nil { 3885 m.logger.Debug("m.communitiesManager.ShouldHandleSyncCommunitySettings error", zap.Error(err)) 3886 return err 3887 } 3888 m.logger.Debug("ShouldHandleSyncCommunity result", zap.Bool("shouldHandle", shouldHandle)) 3889 if !shouldHandle { 3890 return nil 3891 } 3892 3893 communitySettings, err := m.communitiesManager.HandleSyncCommunitySettings(syncCommunitySettings) 3894 if err != nil { 3895 return err 3896 } 3897 3898 messageState.Response.AddCommunitySettings(communitySettings) 3899 return nil 3900 } 3901 3902 func (m *Messenger) InitHistoryArchiveTasks(communities []*communities.Community) { 3903 3904 m.logger.Debug("initializing history archive tasks") 3905 3906 for _, c := range communities { 3907 3908 if c.Joined() { 3909 settings, err := m.communitiesManager.GetCommunitySettingsByID(c.ID()) 3910 if err != nil { 3911 m.logger.Error("failed to get community settings", zap.Error(err)) 3912 continue 3913 } 3914 if !settings.HistoryArchiveSupportEnabled { 3915 m.logger.Debug("history archive support disabled for community", zap.String("id", c.IDString())) 3916 continue 3917 } 3918 3919 // Check if there's already a torrent file for this community and seed it 3920 if m.archiveManager.TorrentFileExists(c.IDString()) { 3921 err = m.archiveManager.SeedHistoryArchiveTorrent(c.ID()) 3922 if err != nil { 3923 m.logger.Error("failed to seed history archive", zap.Error(err)) 3924 } 3925 } 3926 3927 filters, err := m.archiveManager.GetCommunityChatsFilters(c.ID()) 3928 if err != nil { 3929 m.logger.Error("failed to get community chats filters for community", zap.Error(err)) 3930 continue 3931 } 3932 3933 if len(filters) == 0 { 3934 m.logger.Debug("no filters or chats for this community starting interval", zap.String("id", c.IDString())) 3935 go m.archiveManager.StartHistoryArchiveTasksInterval(c, messageArchiveInterval) 3936 continue 3937 } 3938 3939 topics := []types.TopicType{} 3940 3941 for _, filter := range filters { 3942 topics = append(topics, filter.ContentTopic) 3943 } 3944 3945 // First we need to know the timestamp of the latest waku message 3946 // we've received for this community, so we can request messages we've 3947 // possibly missed since then 3948 latestWakuMessageTimestamp, err := m.communitiesManager.GetLatestWakuMessageTimestamp(topics) 3949 if err != nil { 3950 m.logger.Error("failed to get Latest waku message timestamp", zap.Error(err)) 3951 continue 3952 } 3953 3954 if latestWakuMessageTimestamp == 0 { 3955 // This means we don't have any waku messages for this community 3956 // yet, either because no messages were sent in the community so far, 3957 // or because messages haven't reached this node 3958 // 3959 // In this case we default to requesting messages from the store nodes 3960 // for the past 30 days 3961 latestWakuMessageTimestamp = uint64(time.Now().AddDate(0, 0, -30).Unix()) 3962 } 3963 3964 // Request possibly missed waku messages for community 3965 ms := m.getActiveMailserver(c.ID().String()) 3966 _, err = m.syncFiltersFrom(*ms, filters, uint32(latestWakuMessageTimestamp)) 3967 if err != nil { 3968 m.logger.Error("failed to request missing messages", zap.Error(err)) 3969 continue 3970 } 3971 3972 // We figure out the end date of the last created archive and schedule 3973 // the interval for creating future archives 3974 // If the last end date is at least `interval` ago, we create an archive immediately first 3975 lastArchiveEndDateTimestamp, err := m.archiveManager.GetHistoryArchivePartitionStartTimestamp(c.ID()) 3976 if err != nil { 3977 m.logger.Error("failed to get archive partition start timestamp", zap.Error(err)) 3978 continue 3979 } 3980 3981 to := time.Now() 3982 lastArchiveEndDate := time.Unix(int64(lastArchiveEndDateTimestamp), 0) 3983 durationSinceLastArchive := to.Sub(lastArchiveEndDate) 3984 3985 if lastArchiveEndDateTimestamp == 0 { 3986 // No prior messages to be archived, so we just kick off the archive creation loop 3987 // for future archives 3988 go m.archiveManager.StartHistoryArchiveTasksInterval(c, messageArchiveInterval) 3989 } else if durationSinceLastArchive < messageArchiveInterval { 3990 // Last archive is less than `interval` old, wait until `interval` is complete, 3991 // then create archive and kick off archive creation loop for future archives 3992 // Seed current archive in the meantime 3993 err := m.archiveManager.SeedHistoryArchiveTorrent(c.ID()) 3994 if err != nil { 3995 m.logger.Error("failed to seed history archive", zap.Error(err)) 3996 } 3997 timeToNextInterval := messageArchiveInterval - durationSinceLastArchive 3998 3999 m.logger.Debug("starting history archive tasks interval in", zap.Any("timeLeft", timeToNextInterval)) 4000 time.AfterFunc(timeToNextInterval, func() { 4001 err := m.archiveManager.CreateAndSeedHistoryArchive(c.ID(), topics, lastArchiveEndDate, to.Add(timeToNextInterval), messageArchiveInterval, c.Encrypted()) 4002 if err != nil { 4003 m.logger.Error("failed to get create and seed history archive", zap.Error(err)) 4004 } 4005 go m.archiveManager.StartHistoryArchiveTasksInterval(c, messageArchiveInterval) 4006 }) 4007 } else { 4008 // Looks like the last archive was generated more than `interval` 4009 // ago, so lets create a new archive now and then schedule the archive 4010 // creation loop 4011 err := m.archiveManager.CreateAndSeedHistoryArchive(c.ID(), topics, lastArchiveEndDate, to, messageArchiveInterval, c.Encrypted()) 4012 if err != nil { 4013 m.logger.Error("failed to get create and seed history archive", zap.Error(err)) 4014 } 4015 4016 go m.archiveManager.StartHistoryArchiveTasksInterval(c, messageArchiveInterval) 4017 } 4018 } 4019 } 4020 } 4021 4022 func (m *Messenger) enableHistoryArchivesImportAfterDelay() { 4023 go func() { 4024 time.Sleep(importInitialDelay) 4025 m.importDelayer.once.Do(func() { 4026 close(m.importDelayer.wait) 4027 }) 4028 }() 4029 } 4030 4031 func (m *Messenger) checkIfIMemberOfCommunity(communityID types.HexBytes) error { 4032 community, err := m.communitiesManager.GetByID(communityID) 4033 if err != nil { 4034 m.logger.Error("couldn't get community to import archives", zap.Error(err)) 4035 return err 4036 } 4037 4038 if !community.HasMember(&m.identity.PublicKey) { 4039 m.logger.Error("can't import archives when user not a member of community") 4040 return ErrUserNotMember 4041 } 4042 4043 return nil 4044 } 4045 4046 func (m *Messenger) resumeHistoryArchivesImport(communityID types.HexBytes) error { 4047 archiveIDsToImport, err := m.archiveManager.GetMessageArchiveIDsToImport(communityID) 4048 if err != nil { 4049 return err 4050 } 4051 4052 if len(archiveIDsToImport) == 0 { 4053 return nil 4054 } 4055 4056 err = m.checkIfIMemberOfCommunity(communityID) 4057 if err != nil { 4058 return err 4059 } 4060 4061 currentTask := m.archiveManager.GetHistoryArchiveDownloadTask(communityID.String()) 4062 // no need to resume imports if there's already a task ongoing 4063 if currentTask != nil { 4064 return nil 4065 } 4066 4067 // Create new task 4068 task := &communities.HistoryArchiveDownloadTask{ 4069 CancelChan: make(chan struct{}), 4070 Waiter: *new(sync.WaitGroup), 4071 Cancelled: false, 4072 } 4073 4074 m.archiveManager.AddHistoryArchiveDownloadTask(communityID.String(), task) 4075 4076 // this wait groups tracks the ongoing task for a particular community 4077 task.Waiter.Add(1) 4078 4079 go func() { 4080 defer task.Waiter.Done() 4081 err := m.importHistoryArchives(communityID, task.CancelChan) 4082 if err != nil { 4083 m.logger.Error("failed to import history archives", zap.Error(err)) 4084 } 4085 m.config.messengerSignalsHandler.DownloadingHistoryArchivesFinished(types.EncodeHex(communityID)) 4086 }() 4087 return nil 4088 } 4089 4090 func (m *Messenger) SpeedupArchivesImport() { 4091 m.importRateLimiter.SetLimit(rate.Every(importFastRate)) 4092 } 4093 4094 func (m *Messenger) SlowdownArchivesImport() { 4095 m.importRateLimiter.SetLimit(rate.Every(importSlowRate)) 4096 } 4097 4098 func (m *Messenger) importHistoryArchives(communityID types.HexBytes, cancel chan struct{}) error { 4099 importTicker := time.NewTicker(100 * time.Millisecond) 4100 defer importTicker.Stop() 4101 4102 ctx, cancelFunc := context.WithCancel(context.Background()) 4103 go func() { 4104 <-cancel 4105 cancelFunc() 4106 }() 4107 4108 // don't proceed until initial import delay has passed 4109 select { 4110 case <-m.importDelayer.wait: 4111 case <-ctx.Done(): 4112 return nil 4113 } 4114 4115 delayImport := false 4116 4117 importMessageArchivesLoop: 4118 for { 4119 if delayImport { 4120 select { 4121 case <-ctx.Done(): 4122 m.logger.Debug("interrupted importing history archive messages") 4123 return nil 4124 case <-time.After(1 * time.Hour): 4125 delayImport = false 4126 } 4127 } 4128 4129 select { 4130 case <-ctx.Done(): 4131 m.logger.Debug("interrupted importing history archive messages") 4132 return nil 4133 case <-importTicker.C: 4134 err := m.checkIfIMemberOfCommunity(communityID) 4135 if err != nil { 4136 break importMessageArchivesLoop 4137 } 4138 archiveIDsToImport, err := m.archiveManager.GetMessageArchiveIDsToImport(communityID) 4139 if err != nil { 4140 m.logger.Error("couldn't get message archive IDs to import", zap.Error(err)) 4141 return err 4142 } 4143 4144 if len(archiveIDsToImport) == 0 { 4145 m.logger.Debug("no message archives to import") 4146 break importMessageArchivesLoop 4147 } 4148 4149 m.logger.Info("importing message archive", zap.Int("left", len(archiveIDsToImport))) 4150 4151 // only process one archive at a time, so in case of cancel we don't 4152 // wait for all archives to be processed first 4153 downloadedArchiveID := archiveIDsToImport[0] 4154 4155 archiveMessages, err := m.archiveManager.ExtractMessagesFromHistoryArchive(communityID, downloadedArchiveID) 4156 if err != nil { 4157 if errors.Is(err, encryption.ErrHashRatchetGroupIDNotFound) { 4158 // In case we're missing hash ratchet keys, best we can do is 4159 // to wait for them to be received and try import again. 4160 delayImport = true 4161 continue 4162 } 4163 m.logger.Error("failed to extract history archive messages", zap.Error(err)) 4164 continue 4165 } 4166 4167 m.config.messengerSignalsHandler.ImportingHistoryArchiveMessages(types.EncodeHex(communityID)) 4168 4169 for _, messagesChunk := range chunkSlice(archiveMessages, importMessagesChunkSize) { 4170 if err := m.importRateLimiter.Wait(ctx); err != nil { 4171 if !errors.Is(err, context.Canceled) { 4172 m.logger.Error("rate limiter error when handling archive messages", zap.Error(err)) 4173 } 4174 continue importMessageArchivesLoop 4175 } 4176 4177 response, err := m.handleArchiveMessages(messagesChunk) 4178 if err != nil { 4179 m.logger.Error("failed to handle archive messages", zap.Error(err)) 4180 continue importMessageArchivesLoop 4181 } 4182 4183 if !response.IsEmpty() { 4184 notifications := response.Notifications() 4185 response.ClearNotifications() 4186 signal.SendNewMessages(response) 4187 localnotifications.PushMessages(notifications) 4188 } 4189 } 4190 4191 err = m.archiveManager.SetMessageArchiveIDImported(communityID, downloadedArchiveID, true) 4192 if err != nil { 4193 m.logger.Error("failed to mark history message archive as imported", zap.Error(err)) 4194 continue 4195 } 4196 } 4197 } 4198 return nil 4199 } 4200 4201 func (m *Messenger) dispatchMagnetlinkMessage(communityID string) error { 4202 4203 community, err := m.communitiesManager.GetByIDString(communityID) 4204 if err != nil { 4205 return err 4206 } 4207 4208 magnetlink, err := m.archiveManager.GetHistoryArchiveMagnetlink(community.ID()) 4209 if err != nil { 4210 return err 4211 } 4212 4213 magnetLinkMessage := &protobuf.CommunityMessageArchiveMagnetlink{ 4214 Clock: m.getTimesource().GetCurrentTime(), 4215 MagnetUri: magnetlink, 4216 } 4217 4218 encodedMessage, err := proto.Marshal(magnetLinkMessage) 4219 if err != nil { 4220 return err 4221 } 4222 4223 chatID := community.MagnetlinkMessageChannelID() 4224 rawMessage := common.RawMessage{ 4225 LocalChatID: chatID, 4226 Sender: community.PrivateKey(), 4227 Payload: encodedMessage, 4228 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_MESSAGE_ARCHIVE_MAGNETLINK, 4229 SkipGroupMessageWrap: true, 4230 PubsubTopic: community.PubsubTopic(), 4231 Priority: &common.LowPriority, 4232 } 4233 4234 _, err = m.sender.SendPublic(context.Background(), chatID, rawMessage) 4235 if err != nil { 4236 return err 4237 } 4238 4239 err = m.communitiesManager.UpdateCommunityDescriptionMagnetlinkMessageClock(community.ID(), magnetLinkMessage.Clock) 4240 if err != nil { 4241 return err 4242 } 4243 return m.communitiesManager.UpdateMagnetlinkMessageClock(community.ID(), magnetLinkMessage.Clock) 4244 } 4245 4246 func (m *Messenger) EnableCommunityHistoryArchiveProtocol() error { 4247 nodeConfig, err := m.settings.GetNodeConfig() 4248 if err != nil { 4249 return err 4250 } 4251 4252 if nodeConfig.TorrentConfig.Enabled { 4253 return nil 4254 } 4255 4256 nodeConfig.TorrentConfig.Enabled = true 4257 err = m.settings.SaveSetting("node-config", nodeConfig) 4258 if err != nil { 4259 return err 4260 } 4261 4262 m.config.torrentConfig = &nodeConfig.TorrentConfig 4263 m.archiveManager.SetTorrentConfig(&nodeConfig.TorrentConfig) 4264 err = m.archiveManager.StartTorrentClient() 4265 if err != nil { 4266 return err 4267 } 4268 4269 controlledCommunities, err := m.communitiesManager.Controlled() 4270 if err != nil { 4271 return err 4272 } 4273 4274 if len(controlledCommunities) > 0 { 4275 go m.InitHistoryArchiveTasks(controlledCommunities) 4276 } 4277 if m.config.messengerSignalsHandler != nil { 4278 m.config.messengerSignalsHandler.HistoryArchivesProtocolEnabled() 4279 } 4280 return nil 4281 } 4282 4283 func (m *Messenger) DisableCommunityHistoryArchiveProtocol() error { 4284 4285 nodeConfig, err := m.settings.GetNodeConfig() 4286 if err != nil { 4287 return err 4288 } 4289 if !nodeConfig.TorrentConfig.Enabled { 4290 return nil 4291 } 4292 4293 err = m.archiveManager.Stop() 4294 if err != nil { 4295 m.logger.Error("failed to stop torrent manager", zap.Error(err)) 4296 } 4297 4298 nodeConfig.TorrentConfig.Enabled = false 4299 err = m.settings.SaveSetting("node-config", nodeConfig) 4300 m.config.torrentConfig = &nodeConfig.TorrentConfig 4301 m.archiveManager.SetTorrentConfig(&nodeConfig.TorrentConfig) 4302 if err != nil { 4303 return err 4304 } 4305 if m.config.messengerSignalsHandler != nil { 4306 m.config.messengerSignalsHandler.HistoryArchivesProtocolDisabled() 4307 } 4308 return nil 4309 } 4310 4311 func (m *Messenger) GetCommunitiesSettings() ([]communities.CommunitySettings, error) { 4312 settings, err := m.communitiesManager.GetCommunitiesSettings() 4313 if err != nil { 4314 return nil, err 4315 } 4316 return settings, nil 4317 } 4318 4319 func (m *Messenger) SyncCommunitySettings(ctx context.Context, settings *communities.CommunitySettings) error { 4320 4321 if !m.hasPairedDevices() { 4322 return nil 4323 } 4324 4325 clock, chat := m.getLastClockWithRelatedChat() 4326 4327 syncMessage := &protobuf.SyncCommunitySettings{ 4328 Clock: clock, 4329 CommunityId: settings.CommunityID, 4330 HistoryArchiveSupportEnabled: settings.HistoryArchiveSupportEnabled, 4331 } 4332 encodedMessage, err := proto.Marshal(syncMessage) 4333 if err != nil { 4334 return err 4335 } 4336 4337 _, err = m.dispatchMessage(ctx, common.RawMessage{ 4338 LocalChatID: chat.ID, 4339 Payload: encodedMessage, 4340 MessageType: protobuf.ApplicationMetadataMessage_SYNC_COMMUNITY_SETTINGS, 4341 ResendType: common.ResendTypeDataSync, 4342 }) 4343 if err != nil { 4344 return err 4345 } 4346 4347 chat.LastClockValue = clock 4348 return m.saveChat(chat) 4349 } 4350 4351 func (m *Messenger) generateSystemPinnedMessage(pinMessage *common.PinMessage, channel *Chat, clockAndTimestamp uint64, pinnedMessageID string) (*common.Message, *discord.ImportError) { 4352 id, err := generatePinMessageNotificationID(&m.identity.PublicKey, pinMessage, channel) 4353 if err != nil { 4354 m.logger.Warn("failed to generate pin message notification ID", 4355 zap.String("PinMessageId", pinMessage.ID)) 4356 return nil, discord.Warning(err.Error()) 4357 } 4358 systemMessage := &common.Message{ 4359 ChatMessage: &protobuf.ChatMessage{ 4360 Clock: pinMessage.Clock, 4361 Timestamp: clockAndTimestamp, 4362 ChatId: channel.ID, 4363 MessageType: pinMessage.MessageType, 4364 ResponseTo: pinnedMessageID, 4365 ContentType: protobuf.ChatMessage_SYSTEM_MESSAGE_PINNED_MESSAGE, 4366 }, 4367 WhisperTimestamp: clockAndTimestamp, 4368 ID: id, 4369 LocalChatID: channel.ID, 4370 From: pinMessage.From, 4371 Seen: true, 4372 } 4373 4374 return systemMessage, nil 4375 } 4376 4377 func (m *Messenger) pinMessagesToWakuMessages(pinMessages []*common.PinMessage, c *communities.Community) ([]*types.Message, error) { 4378 wakuMessages := make([]*types.Message, 0) 4379 for _, msg := range pinMessages { 4380 4381 filter := m.transport.FilterByChatID(msg.LocalChatID) 4382 encodedPayload, err := proto.Marshal(msg.GetProtobuf()) 4383 if err != nil { 4384 return nil, err 4385 } 4386 wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_PIN_MESSAGE, c.PrivateKey()) 4387 if err != nil { 4388 return nil, err 4389 } 4390 4391 hash := crypto.Keccak256Hash(append([]byte(c.IDString()), wrappedPayload...)) 4392 wakuMessage := &types.Message{ 4393 Sig: crypto.FromECDSAPub(&c.PrivateKey().PublicKey), 4394 Timestamp: uint32(msg.WhisperTimestamp / 1000), 4395 Topic: filter.ContentTopic, 4396 Payload: wrappedPayload, 4397 Padding: []byte{1}, 4398 Hash: hash[:], 4399 ThirdPartyID: msg.ID, // CommunityID + DiscordMessageID 4400 } 4401 wakuMessages = append(wakuMessages, wakuMessage) 4402 } 4403 4404 return wakuMessages, nil 4405 } 4406 4407 func (m *Messenger) chatMessagesToWakuMessages(chatMessages []*common.Message, c *communities.Community) ([]*types.Message, error) { 4408 wakuMessages := make([]*types.Message, 0) 4409 for _, msg := range chatMessages { 4410 4411 filter := m.transport.FilterByChatID(msg.LocalChatID) 4412 encodedPayload, err := proto.Marshal(msg.GetProtobuf()) 4413 if err != nil { 4414 return nil, err 4415 } 4416 4417 wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, c.PrivateKey()) 4418 if err != nil { 4419 return nil, err 4420 } 4421 4422 hash := crypto.Keccak256Hash([]byte(msg.ID)) 4423 wakuMessage := &types.Message{ 4424 Sig: crypto.FromECDSAPub(&c.PrivateKey().PublicKey), 4425 Timestamp: uint32(msg.WhisperTimestamp / 1000), 4426 Topic: filter.ContentTopic, 4427 Payload: wrappedPayload, 4428 Padding: []byte{1}, 4429 Hash: hash[:], 4430 ThirdPartyID: msg.ID, // CommunityID + DiscordMessageID 4431 } 4432 wakuMessages = append(wakuMessages, wakuMessage) 4433 } 4434 4435 return wakuMessages, nil 4436 } 4437 4438 func (m *Messenger) GetCommunityToken(communityID string, chainID int, address string) (*token.CommunityToken, error) { 4439 return m.communitiesManager.GetCommunityToken(communityID, chainID, address) 4440 } 4441 4442 func (m *Messenger) GetCommunityTokenByChainAndAddress(chainID int, address string) (*token.CommunityToken, error) { 4443 return m.communitiesManager.GetCommunityTokenByChainAndAddress(chainID, address) 4444 } 4445 4446 func (m *Messenger) GetCommunityTokens(communityID string) ([]*token.CommunityToken, error) { 4447 return m.communitiesManager.GetCommunityTokens(communityID) 4448 } 4449 4450 func (m *Messenger) GetCommunityPermissionedBalances(request *requests.GetPermissionedBalances) (map[gethcommon.Address][]communities.PermissionedBalance, error) { 4451 err := request.Validate() 4452 if err != nil { 4453 return nil, err 4454 } 4455 4456 accountAddresses, err := m.settings.GetWalletAddresses() 4457 if err != nil { 4458 return nil, err 4459 } 4460 4461 gethAddresses := make([]gethcommon.Address, 0, len(accountAddresses)) 4462 for _, address := range accountAddresses { 4463 gethAddresses = append(gethAddresses, gethcommon.HexToAddress(address.Hex())) 4464 } 4465 4466 return m.communitiesManager.GetPermissionedBalances( 4467 context.Background(), 4468 request.CommunityID, 4469 gethAddresses, 4470 ) 4471 } 4472 4473 func (m *Messenger) GetAllCommunityTokens() ([]*token.CommunityToken, error) { 4474 return m.communitiesManager.GetAllCommunityTokens() 4475 } 4476 4477 func (m *Messenger) SaveCommunityToken(token *token.CommunityToken, croppedImage *images.CroppedImage) (*token.CommunityToken, error) { 4478 return m.communitiesManager.SaveCommunityToken(token, croppedImage) 4479 } 4480 4481 func (m *Messenger) AddCommunityToken(communityID string, chainID int, address string) error { 4482 communityToken, err := m.communitiesManager.GetCommunityToken(communityID, chainID, address) 4483 if err != nil { 4484 return err 4485 } 4486 4487 clock, _ := m.getLastClockWithRelatedChat() 4488 community, err := m.communitiesManager.AddCommunityToken(communityToken, clock) 4489 if err != nil { 4490 return err 4491 } 4492 4493 err = m.syncCommunity(context.Background(), community, m.dispatchMessage) 4494 if err != nil { 4495 return err 4496 } 4497 4498 return nil 4499 } 4500 4501 func (m *Messenger) UpdateCommunityTokenState(chainID int, contractAddress string, deployState token.DeployState) error { 4502 return m.communitiesManager.UpdateCommunityTokenState(chainID, contractAddress, deployState) 4503 } 4504 4505 func (m *Messenger) UpdateCommunityTokenAddress(chainID int, oldContractAddress string, newContractAddress string) error { 4506 return m.communitiesManager.UpdateCommunityTokenAddress(chainID, oldContractAddress, newContractAddress) 4507 } 4508 4509 func (m *Messenger) UpdateCommunityTokenSupply(chainID int, contractAddress string, supply *bigint.BigInt) error { 4510 return m.communitiesManager.UpdateCommunityTokenSupply(chainID, contractAddress, supply) 4511 } 4512 4513 func (m *Messenger) RemoveCommunityToken(chainID int, contractAddress string) error { 4514 return m.communitiesManager.RemoveCommunityToken(chainID, contractAddress) 4515 } 4516 4517 func (m *Messenger) CheckPermissionsToJoinCommunity(request *requests.CheckPermissionToJoinCommunity) (*communities.CheckPermissionToJoinResponse, error) { 4518 if err := request.Validate(); err != nil { 4519 return nil, err 4520 } 4521 var addresses []gethcommon.Address 4522 4523 if len(request.Addresses) == 0 { 4524 accounts, err := m.settings.GetActiveAccounts() 4525 if err != nil { 4526 return nil, err 4527 } 4528 4529 for _, a := range accounts { 4530 if a.IsWalletNonWatchOnlyAccount() { 4531 addresses = append(addresses, gethcommon.HexToAddress(a.Address.Hex())) 4532 } 4533 } 4534 } else { 4535 for _, v := range request.Addresses { 4536 addresses = append(addresses, gethcommon.HexToAddress(v)) 4537 } 4538 } 4539 4540 return m.communitiesManager.CheckPermissionToJoin(request.CommunityID, addresses) 4541 } 4542 4543 func (m *Messenger) getSharedAddresses(communityID types.HexBytes, requestAddresses []string) ([]gethcommon.Address, error) { 4544 addressesMap := make(map[string]struct{}) 4545 4546 for _, v := range requestAddresses { 4547 addressesMap[v] = struct{}{} 4548 } 4549 4550 if len(requestAddresses) == 0 { 4551 sharedAddresses, err := m.GetRevealedAccounts(communityID, common.PubkeyToHex(&m.identity.PublicKey)) 4552 if err != nil { 4553 return nil, err 4554 } 4555 4556 for _, v := range sharedAddresses { 4557 addressesMap[v.Address] = struct{}{} 4558 } 4559 } 4560 4561 if len(addressesMap) == 0 { 4562 accounts, err := m.settings.GetActiveAccounts() 4563 if err != nil { 4564 return nil, err 4565 } 4566 4567 for _, a := range accounts { 4568 addressesMap[a.Address.Hex()] = struct{}{} 4569 } 4570 } 4571 4572 var addresses []gethcommon.Address 4573 for addr := range addressesMap { 4574 addresses = append(addresses, gethcommon.HexToAddress(addr)) 4575 } 4576 4577 return addresses, nil 4578 } 4579 4580 func (m *Messenger) CheckCommunityChannelPermissions(request *requests.CheckCommunityChannelPermissions) (*communities.CheckChannelPermissionsResponse, error) { 4581 if err := request.Validate(); err != nil { 4582 return nil, err 4583 } 4584 4585 addresses, err := m.getSharedAddresses(request.CommunityID, request.Addresses) 4586 if err != nil { 4587 return nil, err 4588 } 4589 4590 return m.communitiesManager.CheckChannelPermissions(request.CommunityID, request.ChatID, addresses) 4591 } 4592 4593 func (m *Messenger) CheckAllCommunityChannelsPermissions(request *requests.CheckAllCommunityChannelsPermissions) (*communities.CheckAllChannelsPermissionsResponse, error) { 4594 if err := request.Validate(); err != nil { 4595 return nil, err 4596 } 4597 4598 addresses, err := m.getSharedAddresses(request.CommunityID, request.Addresses) 4599 if err != nil { 4600 return nil, err 4601 } 4602 4603 return m.communitiesManager.CheckAllChannelsPermissions(request.CommunityID, addresses) 4604 } 4605 4606 func (m *Messenger) GetCommunityCheckChannelPermissionResponses(communityID types.HexBytes) (*communities.CheckAllChannelsPermissionsResponse, error) { 4607 return m.communitiesManager.GetCheckChannelPermissionResponses(communityID) 4608 } 4609 4610 func chunkSlice[T comparable](slice []T, chunkSize int) [][]T { 4611 var chunks [][]T 4612 for i := 0; i < len(slice); i += chunkSize { 4613 end := i + chunkSize 4614 4615 // necessary check to avoid slicing beyond 4616 // slice capacity 4617 if end > len(slice) { 4618 end = len(slice) 4619 } 4620 4621 chunks = append(chunks, slice[i:end]) 4622 } 4623 4624 return chunks 4625 } 4626 4627 func chunkAttachmentsByByteSize(slice []*protobuf.DiscordMessageAttachment, maxFileSizeBytes uint64) [][]*protobuf.DiscordMessageAttachment { 4628 var chunks [][]*protobuf.DiscordMessageAttachment 4629 4630 currentChunkSize := uint64(0) 4631 currentChunk := make([]*protobuf.DiscordMessageAttachment, 0) 4632 4633 for i, attachment := range slice { 4634 payloadBytes := attachment.GetFileSizeBytes() 4635 if currentChunkSize+payloadBytes > maxFileSizeBytes && len(currentChunk) > 0 { 4636 chunks = append(chunks, currentChunk) 4637 currentChunk = make([]*protobuf.DiscordMessageAttachment, 0) 4638 currentChunkSize = uint64(0) 4639 } 4640 currentChunk = append(currentChunk, attachment) 4641 currentChunkSize = currentChunkSize + payloadBytes 4642 if i == len(slice)-1 { 4643 chunks = append(chunks, currentChunk) 4644 } 4645 } 4646 return chunks 4647 } 4648 4649 // startCommunityRekeyLoop creates a 5-minute ticker and starts a routine that attempts to rekey every community every tick 4650 func (m *Messenger) startCommunityRekeyLoop() { 4651 logger := m.logger.Named("CommunityRekeyLoop") 4652 var d time.Duration 4653 if m.communitiesManager.RekeyInterval != 0 { 4654 if m.communitiesManager.RekeyInterval < 10 { 4655 d = time.Nanosecond 4656 } else { 4657 d = m.communitiesManager.RekeyInterval / 10 4658 } 4659 } else { 4660 d = 5 * time.Minute 4661 } 4662 4663 ticker := time.NewTicker(d) 4664 go func() { 4665 for { 4666 select { 4667 case <-ticker.C: 4668 m.rekeyCommunities(logger) 4669 case <-m.quit: 4670 ticker.Stop() 4671 logger.Debug("CommunityRekeyLoop stopped") 4672 return 4673 } 4674 } 4675 }() 4676 } 4677 4678 // rekeyCommunities loops over controlled communities and rekeys if rekey interval elapsed 4679 func (m *Messenger) rekeyCommunities(logger *zap.Logger) { 4680 // TODO in future have a community level rki rather than a global rki 4681 var rekeyInterval time.Duration 4682 if m.communitiesManager.RekeyInterval == 0 { 4683 rekeyInterval = 48 * time.Hour 4684 } else { 4685 rekeyInterval = m.communitiesManager.RekeyInterval 4686 } 4687 4688 shouldRekey := func(hashRatchetGroupID []byte) bool { 4689 key, err := m.sender.GetCurrentKeyForGroup(hashRatchetGroupID) 4690 if err != nil { 4691 logger.Error("failed to get current hash ratchet key", zap.Error(err)) 4692 return false 4693 } 4694 4695 keyDistributedAt := time.UnixMilli(int64(key.Timestamp)) 4696 return time.Now().After(keyDistributedAt.Add(rekeyInterval)) 4697 } 4698 4699 controlledCommunities, err := m.ControlledCommunities() 4700 if err != nil { 4701 logger.Error("error getting communities", zap.Error(err)) 4702 return 4703 } 4704 4705 for _, c := range controlledCommunities { 4706 keyActions := &communities.EncryptionKeyActions{ 4707 CommunityKeyAction: communities.EncryptionKeyAction{}, 4708 ChannelKeysActions: map[string]communities.EncryptionKeyAction{}, 4709 } 4710 4711 if c.Encrypted() && shouldRekey(c.ID()) { 4712 keyActions.CommunityKeyAction = communities.EncryptionKeyAction{ 4713 ActionType: communities.EncryptionKeyRekey, 4714 Members: c.Members(), 4715 } 4716 } 4717 4718 for channelID, channel := range c.Chats() { 4719 if c.ChannelEncrypted(channelID) && shouldRekey([]byte(c.IDString()+channelID)) { 4720 keyActions.ChannelKeysActions[channelID] = communities.EncryptionKeyAction{ 4721 ActionType: communities.EncryptionKeyRekey, 4722 Members: channel.Members, 4723 } 4724 } 4725 } 4726 4727 err = m.communitiesKeyDistributor.Distribute(c, keyActions) 4728 if err != nil { 4729 logger.Error("failed to rekey community", zap.Error(err), zap.String("community ID", c.IDString())) 4730 continue 4731 } 4732 } 4733 } 4734 4735 func (m *Messenger) GetCommunityMembersForWalletAddresses(communityID types.HexBytes, chainID uint64) (map[string]*Contact, error) { 4736 community, err := m.communitiesManager.GetByID(communityID) 4737 if err != nil { 4738 return nil, err 4739 } 4740 4741 membersForAddresses := map[string]*Contact{} 4742 4743 for _, memberPubKey := range community.GetMemberPubkeys() { 4744 memberPubKeyStr := common.PubkeyToHex(memberPubKey) 4745 revealedAccounts, err := m.communitiesManager.GetRevealedAddresses(communityID, memberPubKeyStr) 4746 if err != nil { 4747 return nil, err 4748 } 4749 for _, revealedAccount := range revealedAccounts { 4750 if !slices.Contains(revealedAccount.ChainIds, chainID) { 4751 continue 4752 } 4753 4754 contact, ok := m.allContacts.Load(memberPubKeyStr) 4755 if ok { 4756 membersForAddresses[revealedAccount.Address] = contact 4757 } else { 4758 m.logger.Error("community member is not a contact", zap.String("contact ID", memberPubKeyStr)) 4759 } 4760 } 4761 } 4762 4763 return membersForAddresses, nil 4764 } 4765 4766 func (m *Messenger) processCommunityChanges(messageState *ReceivedMessageState) { 4767 // Process any community changes 4768 pkString := common.PubkeyToHex(&m.identity.PublicKey) 4769 for _, changes := range messageState.Response.CommunityChanges { 4770 if changes.ShouldMemberJoin { 4771 response, err := m.joinCommunity(context.TODO(), changes.Community.ID(), false) 4772 if err != nil { 4773 m.logger.Error("cannot join community", zap.Error(err)) 4774 continue 4775 } 4776 4777 if err := messageState.Response.Merge(response); err != nil { 4778 m.logger.Error("cannot merge join community response", zap.Error(err)) 4779 continue 4780 } 4781 } else if changes.MemberSoftKicked { 4782 m.leaveCommunityOnSoftKick(changes.Community, messageState.Response) 4783 m.shareRevealedAccountsOnSoftKick(changes.Community, messageState.Response) 4784 4785 } else if changes.MemberKicked { 4786 notificationType := ActivityCenterNotificationTypeCommunityKicked 4787 if changes.IsMemberBanned(pkString) { 4788 notificationType = ActivityCenterNotificationTypeCommunityBanned 4789 } 4790 m.leaveCommunityDueToKickOrBan(changes, notificationType, messageState.Response) 4791 } else if changes.IsMemberUnbanned(pkString) { 4792 m.AddActivityCenterNotificationToResponse(changes.Community.IDString(), ActivityCenterNotificationTypeCommunityUnbanned, messageState.Response) 4793 } 4794 } 4795 // Clean up as not used by clients currently 4796 messageState.Response.CommunityChanges = nil 4797 } 4798 4799 func (m *Messenger) PromoteSelfToControlNode(communityID types.HexBytes) (*MessengerResponse, error) { 4800 clock, _ := m.getLastClockWithRelatedChat() 4801 4802 community, err := m.FetchCommunity(&FetchCommunityRequest{ 4803 CommunityKey: types.EncodeHex(communityID), 4804 Shard: nil, 4805 TryDatabase: true, 4806 WaitForResponse: true, 4807 }) 4808 4809 if err != nil { 4810 return nil, err 4811 } 4812 4813 if !communities.HasTokenOwnership(community.Description()) { 4814 return nil, errors.New(ErrOwnerTokenNeeded) 4815 } 4816 4817 changes, err := m.communitiesManager.PromoteSelfToControlNode(community, clock) 4818 if err != nil { 4819 return nil, err 4820 } 4821 4822 var response MessengerResponse 4823 4824 if len(changes.MembersRemoved) > 0 { 4825 requestsToJoin, err := m.communitiesManager.GenerateRequestsToJoinForAutoApprovalOnNewOwnership(changes.Community.ID(), changes.MembersRemoved) 4826 if err != nil { 4827 return nil, err 4828 } 4829 response.AddRequestsToJoinCommunity(requestsToJoin) 4830 } 4831 4832 err = m.syncCommunity(context.Background(), changes.Community, m.dispatchMessage) 4833 if err != nil { 4834 return nil, err 4835 } 4836 4837 response.AddCommunity(changes.Community) 4838 response.CommunityChanges = []*communities.CommunityChanges{changes} 4839 4840 if m.config.messengerSignalsHandler != nil { 4841 m.config.messengerSignalsHandler.MessengerResponse(&response) 4842 } 4843 4844 m.communitiesManager.StartMembersReevaluationLoop(community.ID(), false) 4845 4846 return &response, nil 4847 } 4848 4849 func (m *Messenger) CreateResponseWithACNotification(communityID string, acType ActivityCenterType, isRead bool, tokenDataJSON string) (*MessengerResponse, error) { 4850 tokenData := ActivityTokenData{} 4851 err := json.Unmarshal([]byte(tokenDataJSON), &tokenData) 4852 if len(tokenDataJSON) > 0 && err != nil { 4853 // Only return error when activityDataString is not empty 4854 return nil, err 4855 } 4856 // Activity center notification 4857 notification := &ActivityCenterNotification{ 4858 ID: types.FromHex(uuid.New().String()), 4859 Type: acType, 4860 Timestamp: m.getTimesource().GetCurrentTime(), 4861 CommunityID: communityID, 4862 Read: isRead, 4863 Deleted: false, 4864 UpdatedAt: m.GetCurrentTimeInMillis(), 4865 TokenData: &tokenData, 4866 } 4867 4868 err = m.prepareTokenData(notification.TokenData, m.httpServer) 4869 if err != nil { 4870 return nil, err 4871 } 4872 4873 response := &MessengerResponse{} 4874 4875 err = m.addActivityCenterNotification(response, notification, nil) 4876 if err != nil { 4877 m.logger.Error("failed to save notification", zap.Error(err)) 4878 return response, err 4879 } 4880 4881 return response, nil 4882 } 4883 4884 // SendMessageToControlNode sends a message to the control node of the community. 4885 // use pointer to rawMessage to get the message ID and other updated properties. 4886 func (m *Messenger) SendMessageToControlNode(community *communities.Community, rawMessage *common.RawMessage) ([]byte, error) { 4887 if !community.PublicKey().Equal(community.ControlNode()) { 4888 m.logger.Debug("control node is different with community pubkey", zap.Any("control:", community.ControlNode()), zap.Any("communityPubkey:", community.PublicKey())) 4889 rawMessage.ResendMethod = common.ResendMethodSendPrivate 4890 rawMessage.ResendType = common.ResendTypeDataSync 4891 // MVDS only supports sending encrypted message 4892 rawMessage.SkipEncryptionLayer = false 4893 rawMessage.Recipients = append(rawMessage.Recipients, community.ControlNode()) 4894 return m.sender.SendPrivate(context.Background(), community.ControlNode(), rawMessage) 4895 } 4896 rawMessage.ResendMethod = common.ResendMethodSendCommunityMessage 4897 // Note: There are multiple instances where SendMessageToControlNode is invoked throughout the codebase. 4898 // Additionally, some callers may invoke SendPrivate before SendMessageToControlNode. This could potentially 4899 // lead to a situation where the same raw message is sent using different methods, which, from a code perspective, 4900 // seems erroneous when implementing raw message resending. However, this behavior is intentional and is not considered 4901 // an issue. For a detailed explanation, refer https://github.com/status-im/status-go/pull/4969#issuecomment-2040891184 4902 return m.sender.SendCommunityMessage(context.Background(), rawMessage) 4903 } 4904 4905 func (m *Messenger) AddActivityCenterNotificationToResponse(communityID string, acType ActivityCenterType, response *MessengerResponse) { 4906 // Activity Center notification 4907 notification := &ActivityCenterNotification{ 4908 ID: types.FromHex(uuid.New().String()), 4909 Type: acType, 4910 Timestamp: m.getTimesource().GetCurrentTime(), 4911 CommunityID: communityID, 4912 Read: false, 4913 Deleted: false, 4914 UpdatedAt: m.GetCurrentTimeInMillis(), 4915 } 4916 4917 err := m.addActivityCenterNotification(response, notification, nil) 4918 if err != nil { 4919 m.logger.Error("failed to save notification", zap.Error(err)) 4920 } 4921 } 4922 4923 func (m *Messenger) leaveCommunityDueToKickOrBan(changes *communities.CommunityChanges, acType ActivityCenterType, stateResponse *MessengerResponse) { 4924 response, err := m.kickedOutOfCommunity(changes.Community.ID(), false) 4925 if err != nil { 4926 m.logger.Error("cannot leave community", zap.Error(err)) 4927 return 4928 } 4929 4930 // Activity Center notification 4931 notification := &ActivityCenterNotification{ 4932 ID: types.FromHex(uuid.New().String()), 4933 Type: acType, 4934 Timestamp: m.getTimesource().GetCurrentTime(), 4935 CommunityID: changes.Community.IDString(), 4936 Read: false, 4937 UpdatedAt: m.GetCurrentTimeInMillis(), 4938 } 4939 4940 err = m.addActivityCenterNotification(response, notification, nil) 4941 if err != nil { 4942 m.logger.Error("failed to save notification", zap.Error(err)) 4943 return 4944 } 4945 4946 if err := stateResponse.Merge(response); err != nil { 4947 m.logger.Error("cannot merge leave and notification response", zap.Error(err)) 4948 } 4949 } 4950 4951 func (m *Messenger) GetCommunityMemberAllMessages(request *requests.CommunityMemberMessages) ([]*common.Message, error) { 4952 if err := request.Validate(); err != nil { 4953 return nil, err 4954 } 4955 4956 messages, err := m.persistence.GetCommunityMemberAllMessages(request.MemberPublicKey, request.CommunityID) 4957 if err != nil { 4958 return nil, err 4959 } 4960 4961 for _, message := range messages { 4962 updatedMessages, err := m.persistence.MessagesByResponseTo(message.ID) 4963 if err != nil { 4964 return nil, err 4965 } 4966 4967 messages = append(messages, updatedMessages...) 4968 } 4969 err = m.prepareMessagesList(messages) 4970 if err != nil { 4971 return nil, err 4972 } 4973 return messages, nil 4974 4975 } 4976 4977 func (m *Messenger) DeleteCommunityMemberMessages(request *requests.DeleteCommunityMemberMessages) (*MessengerResponse, error) { 4978 if err := request.Validate(); err != nil { 4979 return nil, err 4980 } 4981 4982 community, err := m.GetCommunityByID(request.CommunityID) 4983 if err != nil { 4984 return nil, err 4985 } 4986 4987 if community == nil { 4988 return nil, communities.ErrOrgNotFound 4989 } 4990 4991 if !community.IsControlNode() && !community.IsPrivilegedMember(m.IdentityPublicKey()) { 4992 return nil, communities.ErrNotEnoughPermissions 4993 } 4994 4995 memberPubKey, err := common.HexToPubkey(request.MemberPubKey) 4996 if err != nil { 4997 return nil, err 4998 } 4999 5000 if community.IsMemberOwner(memberPubKey) && !m.IdentityPublicKey().Equal(memberPubKey) { 5001 return nil, communities.ErrNotOwner 5002 } 5003 5004 deleteMessagesResponse, err := m.deleteCommunityMemberMessages(request.MemberPubKey, request.CommunityID.String(), request.Messages) 5005 if err != nil { 5006 return nil, err 5007 } 5008 5009 deletedMessages := &protobuf.DeleteCommunityMemberMessages{ 5010 Clock: uint64(time.Now().Unix()), 5011 CommunityId: community.ID(), 5012 MemberId: request.MemberPubKey, 5013 Messages: request.Messages, 5014 } 5015 5016 payload, err := proto.Marshal(deletedMessages) 5017 if err != nil { 5018 return nil, err 5019 } 5020 5021 rawMessage := common.RawMessage{ 5022 Payload: payload, 5023 Sender: community.PrivateKey(), 5024 SkipEncryptionLayer: true, 5025 MessageType: protobuf.ApplicationMetadataMessage_DELETE_COMMUNITY_MEMBER_MESSAGES, 5026 PubsubTopic: community.PubsubTopic(), 5027 } 5028 5029 _, err = m.sender.SendPublic(context.Background(), community.IDString(), rawMessage) 5030 5031 return deleteMessagesResponse, err 5032 } 5033 5034 func (m *Messenger) HandleDeleteCommunityMemberMessages(state *ReceivedMessageState, request *protobuf.DeleteCommunityMemberMessages, statusMessage *v1protocol.StatusMessage) error { 5035 community, err := m.communitiesManager.GetByID(request.CommunityId) 5036 if err != nil { 5037 return err 5038 } 5039 5040 if community == nil { 5041 return communities.ErrOrgNotFound 5042 } 5043 5044 if !community.ControlNode().Equal(state.CurrentMessageState.PublicKey) && !community.IsPrivilegedMember(state.CurrentMessageState.PublicKey) { 5045 return communities.ErrNotAuthorized 5046 } 5047 5048 deleteMessagesResponse, err := m.deleteCommunityMemberMessages(request.MemberId, community.IDString(), request.Messages) 5049 if err != nil { 5050 return err 5051 } 5052 5053 return state.Response.Merge(deleteMessagesResponse) 5054 } 5055 5056 func (m *Messenger) leaveCommunityOnSoftKick(community *communities.Community, messengerResponse *MessengerResponse) { 5057 response, err := m.kickedOutOfCommunity(community.ID(), true) 5058 if err != nil { 5059 m.logger.Error("member soft kick error", zap.String("communityID", types.EncodeHex(community.ID())), zap.Error(err)) 5060 } 5061 5062 if err := messengerResponse.Merge(response); err != nil { 5063 m.logger.Error("cannot merge leaveCommunityOnSoftKick response", zap.String("communityID", types.EncodeHex(community.ID())), zap.Error(err)) 5064 } 5065 } 5066 5067 func (m *Messenger) shareRevealedAccountsOnSoftKick(community *communities.Community, messengerResponse *MessengerResponse) { 5068 requestToJoin, err := m.sendSharedAddressToControlNode(community.ControlNode(), community) 5069 if err != nil { 5070 m.logger.Error("share address to control node failed", zap.String("id", types.EncodeHex(community.ID())), zap.Error(err)) 5071 5072 if err == communities.ErrRevealedAccountsAbsent || err == communities.ErrNoRevealedAccountsSignature { 5073 m.AddActivityCenterNotificationToResponse(community.IDString(), ActivityCenterNotificationTypeShareAccounts, messengerResponse) 5074 } 5075 } else { 5076 messengerResponse.AddRequestToJoinCommunity(requestToJoin) 5077 } 5078 } 5079 5080 func (m *Messenger) requestCommunityEncryptionKeys(community *communities.Community, channelIDs []string) error { 5081 m.logger.Debug("request community encryption keys", 5082 zap.String("communityID", community.IDString()), 5083 zap.Strings("channels", channelIDs)) 5084 5085 request := &protobuf.CommunityEncryptionKeysRequest{ 5086 CommunityId: community.ID(), 5087 ChatIds: channelIDs, 5088 } 5089 5090 payload, err := proto.Marshal(request) 5091 if err != nil { 5092 return err 5093 } 5094 5095 rawMessage := &common.RawMessage{ 5096 Payload: payload, 5097 Sender: m.identity, 5098 CommunityID: community.ID(), 5099 SkipEncryptionLayer: true, 5100 MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_ENCRYPTION_KEYS_REQUEST, 5101 } 5102 5103 _, err = m.SendMessageToControlNode(community, rawMessage) 5104 return err 5105 } 5106 5107 func (m *Messenger) startRequestMissingCommunityChannelsHRKeysLoop() { 5108 logger := m.logger.Named("requestMissingCommunityChannelsHRKeysLoop") 5109 5110 go func() { 5111 for { 5112 select { 5113 case <-time.After(5 * time.Minute): 5114 communitiesChannels, err := m.communitiesManager.DetermineChannelsForHRKeysRequest() 5115 if err != nil { 5116 logger.Error("failed to determine channels for encryption keys request", zap.Error(err)) 5117 continue 5118 } 5119 5120 for _, cc := range communitiesChannels { 5121 err := m.requestCommunityEncryptionKeys(cc.Community, cc.ChannelIDs) 5122 if err != nil { 5123 logger.Error("failed to request channels' encryption keys", 5124 zap.String("communityID", cc.Community.IDString()), 5125 zap.Strings("channelIDs", cc.ChannelIDs), 5126 zap.Error(err)) 5127 continue 5128 } 5129 5130 err = m.communitiesManager.UpdateEncryptionKeysRequests(cc.Community.ID(), cc.ChannelIDs) 5131 if err != nil { 5132 logger.Error("failed to update channels' encryption keys requests", 5133 zap.String("communityID", cc.Community.IDString()), 5134 zap.Strings("channelIDs", cc.ChannelIDs), 5135 zap.Error(err)) 5136 } 5137 } 5138 5139 case <-m.quit: 5140 return 5141 } 5142 } 5143 }() 5144 }