2023-09-20 08:37:46 +00:00
|
|
|
package communities
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/ecdsa"
|
2024-07-05 13:43:03 +00:00
|
|
|
"database/sql"
|
|
|
|
"errors"
|
|
|
|
|
|
|
|
"go.uber.org/zap"
|
2023-09-20 08:37:46 +00:00
|
|
|
|
2024-04-03 14:49:57 +00:00
|
|
|
multiaccountscommon "github.com/status-im/status-go/multiaccounts/common"
|
|
|
|
|
2023-09-20 08:37:46 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
2023-12-07 16:27:14 +00:00
|
|
|
"github.com/status-im/status-go/protocol/common"
|
2023-09-20 08:37:46 +00:00
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
|
|
|
)
|
|
|
|
|
2024-07-05 13:43:03 +00:00
|
|
|
var ErrOutdatedSharedRequestToJoinClock = errors.New("outdated clock in shared request to join")
|
|
|
|
var ErrOutdatedSharedRequestToJoinState = errors.New("outdated state in shared request to join")
|
|
|
|
|
2023-09-20 08:37:46 +00:00
|
|
|
type CommunityPrivilegedMemberSyncMessage struct {
|
|
|
|
CommunityPrivateKey *ecdsa.PrivateKey
|
|
|
|
Receivers []*ecdsa.PublicKey
|
|
|
|
CommunityPrivilegedUserSyncMessage *protobuf.CommunityPrivilegedUserSyncMessage
|
|
|
|
}
|
|
|
|
|
2024-07-05 13:43:03 +00:00
|
|
|
func (m *Manager) HandleRequestToJoinPrivilegedUserSyncMessage(message *protobuf.CommunityPrivilegedUserSyncMessage, community *Community) ([]*RequestToJoin, error) {
|
2023-09-20 08:37:46 +00:00
|
|
|
var state RequestToJoinState
|
|
|
|
if message.Type == protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ACCEPT_REQUEST_TO_JOIN {
|
|
|
|
state = RequestToJoinStateAccepted
|
|
|
|
} else {
|
|
|
|
state = RequestToJoinStateDeclined
|
|
|
|
}
|
|
|
|
|
2024-07-05 13:43:03 +00:00
|
|
|
myPk := common.PubkeyToHex(&m.identity.PublicKey)
|
|
|
|
|
2023-09-20 08:37:46 +00:00
|
|
|
requestsToJoin := make([]*RequestToJoin, 0)
|
|
|
|
for signer, requestToJoinProto := range message.RequestToJoin {
|
2024-07-05 13:43:03 +00:00
|
|
|
if signer == myPk {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-09-20 08:37:46 +00:00
|
|
|
requestToJoin := &RequestToJoin{
|
2024-04-03 14:49:57 +00:00
|
|
|
PublicKey: signer,
|
|
|
|
Clock: requestToJoinProto.Clock,
|
|
|
|
ENSName: requestToJoinProto.EnsName,
|
|
|
|
CustomizationColor: multiaccountscommon.IDToColorFallbackToBlue(requestToJoinProto.CustomizationColor),
|
|
|
|
CommunityID: requestToJoinProto.CommunityId,
|
|
|
|
State: state,
|
|
|
|
RevealedAccounts: requestToJoinProto.RevealedAccounts,
|
2023-09-20 08:37:46 +00:00
|
|
|
}
|
|
|
|
requestToJoin.CalculateID()
|
|
|
|
|
2024-07-05 13:43:03 +00:00
|
|
|
err := m.processPrivilegedUserSharedRequestToJoin(community, requestToJoin)
|
|
|
|
if err != nil {
|
|
|
|
m.logger.Warn("error to handle shared request to join",
|
|
|
|
zap.String("communityID", community.IDString()),
|
|
|
|
zap.String("requestToJoinID", types.Bytes2Hex(requestToJoin.ID)),
|
|
|
|
zap.String("publicKey", requestToJoin.PublicKey),
|
|
|
|
zap.String("error", err.Error()))
|
|
|
|
continue
|
2023-12-07 16:27:14 +00:00
|
|
|
}
|
|
|
|
|
2023-09-20 08:37:46 +00:00
|
|
|
requestsToJoin = append(requestsToJoin, requestToJoin)
|
|
|
|
}
|
|
|
|
|
|
|
|
return requestsToJoin, nil
|
|
|
|
}
|
|
|
|
|
2024-07-05 13:43:03 +00:00
|
|
|
func (m *Manager) HandleSyncAllRequestToJoinForNewPrivilegedMember(message *protobuf.CommunityPrivilegedUserSyncMessage, community *Community) ([]*RequestToJoin, error) {
|
2023-12-07 16:27:14 +00:00
|
|
|
nonAcceptedRequestsToJoin := []*RequestToJoin{}
|
|
|
|
myPk := common.PubkeyToHex(&m.identity.PublicKey)
|
|
|
|
|
2023-09-20 08:37:46 +00:00
|
|
|
for _, syncRequestToJoin := range message.SyncRequestsToJoin {
|
2024-07-05 13:43:03 +00:00
|
|
|
if syncRequestToJoin.PublicKey == myPk {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-09-20 08:37:46 +00:00
|
|
|
requestToJoin := new(RequestToJoin)
|
|
|
|
requestToJoin.InitFromSyncProtobuf(syncRequestToJoin)
|
|
|
|
|
2024-07-05 13:43:03 +00:00
|
|
|
err := m.processPrivilegedUserSharedRequestToJoin(community, requestToJoin)
|
|
|
|
if err != nil {
|
|
|
|
m.logger.Warn("error to handle shared request to join from sync all requests to join msg",
|
|
|
|
zap.String("communityID", community.IDString()),
|
|
|
|
zap.String("requestToJoinID", types.Bytes2Hex(requestToJoin.ID)),
|
|
|
|
zap.String("publicKey", requestToJoin.PublicKey),
|
|
|
|
zap.String("error", err.Error()))
|
|
|
|
continue
|
2023-09-20 08:37:46 +00:00
|
|
|
}
|
2023-12-07 16:27:14 +00:00
|
|
|
|
|
|
|
if requestToJoin.State != RequestToJoinStateAccepted {
|
|
|
|
nonAcceptedRequestsToJoin = append(nonAcceptedRequestsToJoin, requestToJoin)
|
|
|
|
}
|
2023-09-20 08:37:46 +00:00
|
|
|
}
|
2023-12-07 16:27:14 +00:00
|
|
|
return nonAcceptedRequestsToJoin, nil
|
2023-09-20 08:37:46 +00:00
|
|
|
}
|
2024-07-05 13:43:03 +00:00
|
|
|
|
|
|
|
func (m *Manager) HandleEditSharedAddressesPrivilegedUserSyncMessage(message *protobuf.CommunityPrivilegedUserSyncMessage, community *Community) error {
|
|
|
|
if !(community.IsTokenMaster() || community.IsOwner()) {
|
|
|
|
return ErrNotEnoughPermissions
|
|
|
|
}
|
|
|
|
|
|
|
|
publicKey := message.SyncEditSharedAddresses.PublicKey
|
|
|
|
editSharedAddress := message.SyncEditSharedAddresses.EditSharedAddress
|
|
|
|
if err := community.ValidateEditSharedAddresses(publicKey, editSharedAddress); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return m.handleCommunityEditSharedAddresses(publicKey, community.ID(), editSharedAddress.RevealedAccounts, message.Clock)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Manager) processPrivilegedUserSharedRequestToJoin(community *Community, requestToJoin *RequestToJoin) error {
|
|
|
|
existingRequestToJoin, err := m.persistence.GetCommunityRequestToJoinWithRevealedAddresses(requestToJoin.PublicKey, community.ID())
|
|
|
|
if err != nil && err != sql.ErrNoRows {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
statusUpdate := existingRequestToJoin != nil && existingRequestToJoin.Clock == requestToJoin.Clock
|
|
|
|
|
|
|
|
if existingRequestToJoin != nil && existingRequestToJoin.Clock > requestToJoin.Clock {
|
|
|
|
return ErrOutdatedSharedRequestToJoinClock
|
|
|
|
}
|
|
|
|
|
|
|
|
revealedAccountsExists := requestToJoin.RevealedAccounts != nil && len(requestToJoin.RevealedAccounts) > 0
|
|
|
|
|
|
|
|
if member, memberExists := community.Members()[requestToJoin.PublicKey]; memberExists && member.LastUpdateClock > requestToJoin.Clock {
|
|
|
|
return ErrOutdatedSharedRequestToJoinClock
|
|
|
|
}
|
|
|
|
|
|
|
|
if statusUpdate {
|
|
|
|
isCurrentStateAccepted := existingRequestToJoin.State == RequestToJoinStateAccepted
|
|
|
|
isNewRequestAccepted := requestToJoin.State == RequestToJoinStateAccepted
|
|
|
|
isNewAcceptedRequestWithoutAccounts := isNewRequestAccepted && !revealedAccountsExists
|
|
|
|
isCurrentStateDeclined := existingRequestToJoin.State == RequestToJoinStateDeclined
|
|
|
|
|
|
|
|
if (isCurrentStateAccepted && (!isNewRequestAccepted || isNewAcceptedRequestWithoutAccounts)) ||
|
|
|
|
(isCurrentStateDeclined && !isNewRequestAccepted) {
|
|
|
|
return ErrOutdatedSharedRequestToJoinState
|
|
|
|
}
|
|
|
|
|
|
|
|
err = m.persistence.SetRequestToJoinState(requestToJoin.PublicKey, community.ID(), requestToJoin.State)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err = m.persistence.SaveRequestToJoin(requestToJoin)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we are a token master or owner without private key and we received request to join without
|
|
|
|
// revealed accounts - there is a chance, that we lost our role and did't get
|
|
|
|
// CommunityDescription update. But it also can indicate, that we received an outdated
|
|
|
|
// request to join, when we were admins
|
|
|
|
// Decision - is not to delete existing revealed accounts
|
|
|
|
if (community.IsTokenMaster() || community.IsOwner()) && !revealedAccountsExists {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
err = m.persistence.RemoveRequestToJoinRevealedAddresses(requestToJoin.ID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if revealedAccountsExists {
|
|
|
|
return m.persistence.SaveRequestToJoinRevealedAddresses(requestToJoin.ID, requestToJoin.RevealedAccounts)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|