feat: support signing of a join/edit community request from within the app or keycard

This commit is contained in:
Sale Djenic 2023-10-20 08:21:41 +02:00 committed by saledjenic
parent cb3a88f93a
commit 11a3612290
14 changed files with 316 additions and 167 deletions

View File

@ -54,7 +54,23 @@ var zeroAddress = types.Address{}
type SignParams struct {
Data interface{} `json:"data"`
Address string `json:"account"`
Password string `json:"password"`
Password string `json:"password,omitempty"`
}
func (sp *SignParams) Validate(checkPassword bool) error {
if len(sp.Address) != 2*types.AddressLength+2 {
return errors.New("address has to be provided")
}
if sp.Data == "" {
return errors.New("data has to be provided")
}
if checkPassword && sp.Password == "" {
return errors.New("password has to be provided")
}
return nil
}
type RecoverParams struct {

View File

@ -3248,25 +3248,32 @@ func (m *Manager) SaveRequestToJoinAndCommunity(requestToJoin *RequestToJoin, co
return community, requestToJoin, nil
}
func (m *Manager) CreateRequestToJoin(requester *ecdsa.PublicKey, request *requests.RequestToJoinCommunity) (*Community, *RequestToJoin, error) {
community, err := m.GetByID(request.CommunityID)
func (m *Manager) CheckCommunityForJoining(communityID types.HexBytes) (*Community, error) {
community, err := m.GetByID(communityID)
if err != nil {
return nil, nil, err
return nil, err
}
err = community.updateCommunityDescriptionByEvents()
if err != nil {
return nil, nil, err
if community == nil {
return nil, ErrOrgNotFound
}
// We don't allow requesting access if already joined
if community.Joined() {
return nil, nil, ErrAlreadyJoined
return nil, ErrAlreadyJoined
}
err = community.updateCommunityDescriptionByEvents()
if err != nil {
return nil, err
}
return community, nil
}
func (m *Manager) CreateRequestToJoin(request *requests.RequestToJoinCommunity) *RequestToJoin {
clock := uint64(time.Now().Unix())
requestToJoin := &RequestToJoin{
PublicKey: common.PubkeyToHex(requester),
PublicKey: common.PubkeyToHex(&m.identity.PublicKey),
Clock: clock,
ENSName: request.ENSName,
CommunityID: request.CommunityID,
@ -3277,7 +3284,21 @@ func (m *Manager) CreateRequestToJoin(requester *ecdsa.PublicKey, request *reque
requestToJoin.CalculateID()
return community, requestToJoin, nil
addSignature := len(request.Signatures) == len(request.AddressesToReveal)
for i := range request.AddressesToReveal {
revealedAcc := &protobuf.RevealedAccount{
Address: request.AddressesToReveal[i],
IsAirdropAddress: types.HexToAddress(request.AddressesToReveal[i]) == types.HexToAddress(request.AirdropAddress),
}
if addSignature {
revealedAcc.Signature = request.Signatures[i]
}
requestToJoin.RevealedAccounts = append(requestToJoin.RevealedAccounts, revealedAcc)
}
return requestToJoin
}
func (m *Manager) SaveRequestToJoin(request *RequestToJoin) error {

View File

@ -122,19 +122,17 @@ func setUpCommunityAndRoles(base CommunityEventsTestsInterface, role protobuf.Co
request := &requests.RequestToJoinCommunity{
CommunityID: community.ID(),
AddressesToReveal: []string{eventsSenderAccountAddress},
Password: accountPassword,
AirdropAddress: eventsSenderAccountAddress,
}
joinCommunity(suite, community, base.GetControlNode(), base.GetEventSender(), request)
joinCommunity(suite, community, base.GetControlNode(), base.GetEventSender(), request, accountPassword)
refreshMessengerResponses(base)
request = &requests.RequestToJoinCommunity{
CommunityID: community.ID(),
AddressesToReveal: []string{aliceAccountAddress},
Password: accountPassword,
AirdropAddress: aliceAccountAddress,
}
joinCommunity(suite, community, base.GetControlNode(), base.GetMember(), request)
joinCommunity(suite, community, base.GetControlNode(), base.GetMember(), request, accountPassword)
refreshMessengerResponses(base)
// grant permissions to the event sender
@ -426,7 +424,6 @@ func setUpOnRequestCommunityAndRoles(base CommunityEventsTestsInterface, role pr
CommunityID: community.ID(),
AddressesToReveal: []string{eventsSenderAccountAddress},
ENSName: "eventSender",
Password: accountPassword,
AirdropAddress: eventsSenderAccountAddress,
}
@ -436,7 +433,6 @@ func setUpOnRequestCommunityAndRoles(base CommunityEventsTestsInterface, role pr
CommunityID: community.ID(),
AddressesToReveal: []string{aliceAccountAddress},
ENSName: "alice",
Password: accountPassword,
AirdropAddress: aliceAccountAddress,
}
joinOnRequestCommunity(s, community, base.GetControlNode(), base.GetMember(), requestMember)
@ -2040,7 +2036,6 @@ func testJoinedPrivilegedMemberReceiveRequestsToJoin(base CommunityEventsTestsIn
CommunityID: community.ID(),
AddressesToReveal: []string{bobAccountAddress},
ENSName: "bob",
Password: accountPassword,
AirdropAddress: bobAccountAddress,
}
@ -2050,7 +2045,6 @@ func testJoinedPrivilegedMemberReceiveRequestsToJoin(base CommunityEventsTestsIn
CommunityID: community.ID(),
AddressesToReveal: []string{eventsSenderAccountAddress},
ENSName: "newPrivilegedUser",
Password: accountPassword,
AirdropAddress: eventsSenderAccountAddress,
}
@ -2118,7 +2112,6 @@ func testMemberReceiveRequestsToJoinAfterGettingNewRole(base CommunityEventsTest
CommunityID: community.ID(),
AddressesToReveal: []string{aliceAccountAddress},
ENSName: "alice",
Password: accountPassword,
AirdropAddress: aliceAccountAddress,
}
@ -2128,7 +2121,6 @@ func testMemberReceiveRequestsToJoinAfterGettingNewRole(base CommunityEventsTest
CommunityID: community.ID(),
AddressesToReveal: []string{bobAccountAddress},
ENSName: "bob",
Password: accountPassword,
AirdropAddress: bobAccountAddress,
}
@ -2138,7 +2130,6 @@ func testMemberReceiveRequestsToJoinAfterGettingNewRole(base CommunityEventsTest
CommunityID: community.ID(),
AddressesToReveal: []string{eventsSenderAccountAddress},
ENSName: "eventSender",
Password: accountPassword,
AirdropAddress: eventsSenderAccountAddress,
}

View File

@ -429,7 +429,30 @@ func advertiseCommunityTo(s *suite.Suite, community *communities.Community, owne
s.Require().NoError(err)
}
func joinCommunity(s *suite.Suite, community *communities.Community, owner *Messenger, user *Messenger, request *requests.RequestToJoinCommunity) {
func joinCommunity(s *suite.Suite, community *communities.Community, owner *Messenger, user *Messenger, request *requests.RequestToJoinCommunity, password string) {
if password != "" {
signingParams, err := user.GenerateJoiningCommunityRequestsForSigning(common.PubkeyToHex(&user.identity.PublicKey), community.ID(), request.AddressesToReveal)
s.Require().NoError(err)
for i := range signingParams {
signingParams[i].Password = password
}
signatures, err := user.SignData(signingParams)
s.Require().NoError(err)
updateAddresses := len(request.AddressesToReveal) == 0
if updateAddresses {
request.AddressesToReveal = make([]string, len(signingParams))
}
for i := range signingParams {
request.AddressesToReveal[i] = signingParams[i].Address
request.Signatures = append(request.Signatures, types.FromHex(signatures[i]))
}
if updateAddresses {
request.AirdropAddress = request.AddressesToReveal[0]
}
}
response, err := user.RequestToJoinCommunity(request)
s.Require().NoError(err)
s.Require().NotNil(response)

View File

@ -95,7 +95,7 @@ func (s *MessengerCommunitiesSignersSuite) advertiseCommunityTo(controlNode *Mes
func (s *MessengerCommunitiesSignersSuite) joinCommunity(controlNode *Messenger, community *communities.Community, user *Messenger) {
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
joinCommunity(&s.Suite, community, controlNode, user, request)
joinCommunity(&s.Suite, community, controlNode, user, request, "")
}
func (s *MessengerCommunitiesSignersSuite) joinOnRequestCommunity(controlNode *Messenger, community *communities.Community, user *Messenger) {

View File

@ -392,7 +392,7 @@ func (s *MessengerCommunitiesSuite) advertiseCommunityTo(community *communities.
func (s *MessengerCommunitiesSuite) joinCommunity(community *communities.Community, owner *Messenger, user *Messenger) {
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
joinCommunity(&s.Suite, community, owner, user, request)
joinCommunity(&s.Suite, community, owner, user, request, "")
}
func (s *MessengerCommunitiesSuite) TestCommunityContactCodeAdvertisement() {
@ -3246,7 +3246,7 @@ func (s *MessengerCommunitiesSuite) TestCommunityBanUserRequestToJoin() {
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
// We try to join the org
_, rtj, err := s.alice.communitiesManager.CreateRequestToJoin(&s.alice.identity.PublicKey, request)
rtj := s.alice.communitiesManager.CreateRequestToJoin(request)
s.Require().NoError(err)

View File

@ -196,8 +196,8 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) joinCommunityWithAirdropAddr
airdropAddress = addresses[0]
}
request := &requests.RequestToJoinCommunity{CommunityID: community.ID(), Password: passwdHash, AddressesToReveal: addresses, AirdropAddress: airdropAddress}
joinCommunity(&s.Suite, community, s.owner, user, request)
request := &requests.RequestToJoinCommunity{CommunityID: community.ID(), AddressesToReveal: addresses, AirdropAddress: airdropAddress}
joinCommunity(&s.Suite, community, s.owner, user, request, passwdHash)
}
func (s *MessengerCommunitiesTokenPermissionsSuite) advertiseCommunityTo(community *communities.Community, user *Messenger) {
@ -529,8 +529,30 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) TestEditSharedAddresses() {
s.Require().Equal(alicesRevealedAccounts[0].Address, aliceAddress2)
s.Require().Equal(true, alicesRevealedAccounts[0].IsAirdropAddress)
request := &requests.EditSharedAddresses{CommunityID: community.ID(), AddressesToReveal: []string{aliceAddress1}, AirdropAddress: aliceAddress1}
signingParams, err := s.alice.GenerateJoiningCommunityRequestsForSigning(common.PubkeyToHex(&s.alice.identity.PublicKey), community.ID(), request.AddressesToReveal)
s.Require().NoError(err)
passwdHash := types.EncodeHex(crypto.Keccak256([]byte(alicePassword)))
request := &requests.EditSharedAddresses{CommunityID: community.ID(), Password: passwdHash, AddressesToReveal: []string{aliceAddress1}, AirdropAddress: aliceAddress1}
for i := range signingParams {
signingParams[i].Password = passwdHash
}
signatures, err := s.alice.SignData(signingParams)
s.Require().NoError(err)
updateAddresses := len(request.AddressesToReveal) == 0
if updateAddresses {
request.AddressesToReveal = make([]string, len(signingParams))
}
for i := range signingParams {
request.AddressesToReveal[i] = signingParams[i].Address
request.Signatures = append(request.Signatures, types.FromHex(signatures[i]))
}
if updateAddresses {
request.AirdropAddress = request.AddressesToReveal[0]
}
response, err := s.alice.EditSharedAddressesForCommunity(request)
s.Require().NoError(err)
s.Require().NotNil(response)
@ -670,8 +692,7 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) TestBecomeMemberPermissions(
s.Require().ErrorContains(err, "no messages")
// bob tries to join, but he doesn't satisfy so the request isn't sent
passwdHash := types.EncodeHex(crypto.Keccak256([]byte(bobPassword)))
request := &requests.RequestToJoinCommunity{CommunityID: community.ID(), Password: passwdHash, AddressesToReveal: []string{bobAddress}, AirdropAddress: bobAddress}
request := &requests.RequestToJoinCommunity{CommunityID: community.ID(), AddressesToReveal: []string{bobAddress}, AirdropAddress: bobAddress}
_, err = s.bob.RequestToJoinCommunity(request)
s.Require().Error(err)
s.Require().ErrorContains(err, "permission to join not satisfied")

View File

@ -34,7 +34,7 @@ func (s *MessengerActivityCenterMessageSuite) advertiseCommunityTo(community *co
func (s *MessengerActivityCenterMessageSuite) joinCommunity(community *communities.Community, owner *Messenger, user *Messenger) {
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
joinCommunity(&s.Suite, community, owner, user, request)
joinCommunity(&s.Suite, community, owner, user, request, "")
}
type MessengerActivityCenterMessageSuite struct {

View File

@ -982,17 +982,15 @@ func (m *Messenger) SetMutePropertyOnChatsByCategory(request *requests.MuteCateg
return nil
}
// getAccountsToShare is used to get the wallet accounts to share either when requesting to join a community or when editing
// requestToJoinID can be empty when editing
func (m *Messenger) getAccountsToShare(addressesToReveal []string, airdropAddress string, communityID types.HexBytes, password string, requestToJoinID []byte) (map[gethcommon.Address]*protobuf.RevealedAccount, []gethcommon.Address, error) {
// Generates a single hash for each address that needs to be revealed to a community.
// Each hash needs to be signed.
// The order of retuned hashes corresponds to the order of addresses in addressesToReveal.
func (m *Messenger) generateCommunityRequestsForSigning(memberPubKey string, communityID types.HexBytes, addressesToReveal []string, isEdit bool) ([]account.SignParams, error) {
walletAccounts, err := m.settings.GetActiveAccounts()
if err != nil {
return nil, nil, err
return nil, err
}
revealedAccounts := make(map[gethcommon.Address]*protobuf.RevealedAccount)
revealedAddresses := make([]gethcommon.Address, 0)
containsAddress := func(addresses []string, targetAddress string) bool {
for _, address := range addresses {
if types.HexToAddress(address) == types.HexToAddress(targetAddress) {
@ -1002,7 +1000,8 @@ func (m *Messenger) getAccountsToShare(addressesToReveal []string, airdropAddres
return false
}
for i, walletAccount := range walletAccounts {
msgsToSign := make([]account.SignParams, 0)
for _, walletAccount := range walletAccounts {
if walletAccount.Chat || walletAccount.Type == accounts.AccountTypeWatch {
continue
}
@ -1011,65 +1010,114 @@ func (m *Messenger) getAccountsToShare(addressesToReveal []string, airdropAddres
continue
}
verifiedAccount, err := m.accountsManager.GetVerifiedWalletAccount(m.settings, walletAccount.Address.Hex(), password)
if err != nil {
return nil, nil, err
requestID := []byte{}
if !isEdit {
requestID = communities.CalculateRequestID(memberPubKey, communityID)
}
msgsToSign = append(msgsToSign, account.SignParams{
Data: types.EncodeHex(crypto.Keccak256(m.IdentityPublicKeyCompressed(), communityID, requestID)),
Address: walletAccount.Address.Hex(),
})
}
messageToSign := types.EncodeHex(crypto.Keccak256(m.IdentityPublicKeyCompressed(), communityID, requestToJoinID))
signParams := account.SignParams{
Data: messageToSign,
Address: verifiedAccount.Address.Hex(),
Password: password,
}
signatureBytes, err := m.accountsManager.Sign(signParams, verifiedAccount)
if err != nil {
return nil, nil, err
return msgsToSign, nil
}
revealedAddress := gethcommon.HexToAddress(verifiedAccount.Address.Hex())
revealedAddresses = append(revealedAddresses, revealedAddress)
address := verifiedAccount.Address.Hex()
isAirdropAddress := types.HexToAddress(address) == types.HexToAddress(airdropAddress)
if airdropAddress == "" {
isAirdropAddress = i == 0
func (m *Messenger) GenerateJoiningCommunityRequestsForSigning(memberPubKey string, communityID types.HexBytes, addressesToReveal []string) ([]account.SignParams, error) {
if len(communityID) == 0 {
return nil, errors.New("communityID has to be provided")
}
revealedAccounts[revealedAddress] = &protobuf.RevealedAccount{
Address: address,
IsAirdropAddress: isAirdropAddress,
Signature: signatureBytes,
ChainIds: make([]uint64, 0),
return m.generateCommunityRequestsForSigning(memberPubKey, communityID, addressesToReveal, false)
}
func (m *Messenger) GenerateEditCommunityRequestsForSigning(memberPubKey string, communityID types.HexBytes, addressesToReveal []string) ([]account.SignParams, error) {
return m.generateCommunityRequestsForSigning(memberPubKey, communityID, addressesToReveal, true)
}
return revealedAccounts, revealedAddresses, nil
// Signs the provided messages with the provided accounts and password.
// Provided accounts must not belong to a keypair that is migrated to a keycard.
// Otherwise, the signing will fail, cause such accounts should be signed with a keycard.
func (m *Messenger) SignData(signParams []account.SignParams) ([]string, error) {
signatures := make([]string, len(signParams))
for i, param := range signParams {
if err := param.Validate(true); err != nil {
return nil, err
}
account, err := m.settings.GetAccountByAddress(types.HexToAddress(param.Address))
if err != nil {
return nil, err
}
if account.Chat || account.Type == accounts.AccountTypeWatch {
return nil, errors.New("cannot join a community using profile chat or watch-only account")
}
keypair, err := m.settings.GetKeypairByKeyUID(account.KeyUID)
if err != nil {
return nil, err
}
if keypair.MigratedToKeycard() {
return nil, errors.New("signing a joining community request for accounts migrated to keycard must be done with a keycard")
}
verifiedAccount, err := m.accountsManager.GetVerifiedWalletAccount(m.settings, param.Address, param.Password)
if err != nil {
return nil, err
}
signature, err := m.accountsManager.Sign(param, verifiedAccount)
if err != nil {
return nil, err
}
signatures[i] = types.EncodeHex(signature)
}
return signatures, nil
}
func (m *Messenger) RequestToJoinCommunity(request *requests.RequestToJoinCommunity) (*MessengerResponse, error) {
// TODO: Because of changes that need to be done in tests, calling this function and providing `request` without `AddressesToReveal`
// is not an error, but it should be.
logger := m.logger.Named("RequestToJoinCommunity")
if err := request.Validate(); err != nil {
if err := request.Validate(len(request.AddressesToReveal) > 0); err != nil {
logger.Debug("request failed to validate", zap.Error(err), zap.Any("request", request))
return nil, err
}
if request.Password != "" {
walletAccounts, err := m.settings.GetActiveAccounts()
requestToJoin := m.communitiesManager.CreateRequestToJoin(request)
if len(request.AddressesToReveal) > 0 {
revealedAddresses := make([]gethcommon.Address, 0)
for _, addr := range request.AddressesToReveal {
revealedAddresses = append(revealedAddresses, gethcommon.HexToAddress(addr))
}
permissions, err := m.communitiesManager.CheckPermissionToJoin(request.CommunityID, revealedAddresses)
if err != nil {
return nil, err
}
if len(walletAccounts) > 0 {
_, err := m.accountsManager.GetVerifiedWalletAccount(m.settings, walletAccounts[0].Address.Hex(), request.Password)
if err != nil {
return nil, err
if !permissions.Satisfied {
return nil, errors.New("permission to join not satisfied")
}
for _, accountAndChainIDs := range permissions.ValidCombinations {
for i := range requestToJoin.RevealedAccounts {
if gethcommon.HexToAddress(requestToJoin.RevealedAccounts[i].Address) == accountAndChainIDs.Address {
requestToJoin.RevealedAccounts[i].ChainIds = accountAndChainIDs.ChainIDs
}
}
}
}
displayName, err := m.settings.DisplayName()
community, err := m.communitiesManager.CheckCommunityForJoining(request.CommunityID)
if err != nil {
return nil, err
}
community, requestToJoin, err := m.communitiesManager.CreateRequestToJoin(&m.identity.PublicKey, request)
displayName, err := m.settings.DisplayName()
if err != nil {
return nil, err
}
@ -1078,40 +1126,8 @@ func (m *Messenger) RequestToJoinCommunity(request *requests.RequestToJoinCommun
Clock: requestToJoin.Clock,
EnsName: requestToJoin.ENSName,
DisplayName: displayName,
CommunityId: community.ID(),
RevealedAccounts: make([]*protobuf.RevealedAccount, 0),
}
// find wallet accounts and attach wallet addresses and
// signatures to request
if request.Password != "" {
revealedAccounts, revealedAddresses, err := m.getAccountsToShare(
request.AddressesToReveal,
request.AirdropAddress,
request.CommunityID,
request.Password,
requestToJoin.ID,
)
if err != nil {
return nil, err
}
response, err := m.communitiesManager.CheckPermissionToJoin(community.ID(), revealedAddresses)
if err != nil {
return nil, err
}
if !response.Satisfied {
return nil, errors.New("permission to join not satisfied")
}
for _, accountAndChainIDs := range response.ValidCombinations {
revealedAccounts[accountAndChainIDs.Address].ChainIds = accountAndChainIDs.ChainIDs
}
for _, revealedAccount := range revealedAccounts {
requestToJoinProto.RevealedAccounts = append(requestToJoinProto.RevealedAccounts, revealedAccount)
requestToJoin.RevealedAccounts = append(requestToJoinProto.RevealedAccounts, revealedAccount)
}
CommunityId: request.CommunityID,
RevealedAccounts: requestToJoin.RevealedAccounts,
}
community, _, err = m.communitiesManager.SaveRequestToJoinAndCommunity(requestToJoin, community)
@ -1223,31 +1239,26 @@ func (m *Messenger) EditSharedAddressesForCommunity(request *requests.EditShared
logger.Debug("request failed to validate", zap.Error(err), zap.Any("request", request))
return nil, err
}
// verify wallet password is there
if request.Password == "" {
return nil, errors.New("password is necessary to use this function")
}
community, err := m.communitiesManager.GetByID(request.CommunityID)
if err != nil {
return nil, err
}
walletAccounts, err := m.settings.GetActiveAccounts()
if err != nil {
return nil, err
}
if len(walletAccounts) > 0 {
_, err := m.accountsManager.GetVerifiedWalletAccount(m.settings, walletAccounts[0].Address.Hex(), request.Password)
if err != nil {
return nil, err
}
}
if !community.HasMember(m.IdentityPublicKey()) {
return nil, errors.New("not part of the community")
}
revealedAddresses := make([]gethcommon.Address, 0)
for _, addr := range request.AddressesToReveal {
revealedAddresses = append(revealedAddresses, gethcommon.HexToAddress(addr))
}
checkPermissionResponse, err := m.communitiesManager.CheckPermissionToJoin(community.ID(), revealedAddresses)
if err != nil {
return nil, err
}
member := community.GetMember(m.IdentityPublicKey())
requestToEditRevealedAccountsProto := &protobuf.CommunityEditSharedAddresses{
@ -1255,30 +1266,22 @@ func (m *Messenger) EditSharedAddressesForCommunity(request *requests.EditShared
CommunityId: community.ID(),
RevealedAccounts: make([]*protobuf.RevealedAccount, 0),
}
// find wallet accounts and attach wallet addresses and
// signatures to request
revealedAccounts, revealedAddresses, err := m.getAccountsToShare(
request.AddressesToReveal,
request.AirdropAddress,
request.CommunityID,
request.Password,
[]byte{},
)
if err != nil {
return nil, err
}
checkPermissionResponse, err := m.communitiesManager.CheckPermissionToJoin(community.ID(), revealedAddresses)
if err != nil {
return nil, err
for i := range request.AddressesToReveal {
revealedAcc := &protobuf.RevealedAccount{
Address: request.AddressesToReveal[i],
IsAirdropAddress: types.HexToAddress(request.AddressesToReveal[i]) == types.HexToAddress(request.AirdropAddress),
Signature: request.Signatures[i],
}
for _, accountAndChainIDs := range checkPermissionResponse.ValidCombinations {
revealedAccounts[accountAndChainIDs.Address].ChainIds = accountAndChainIDs.ChainIDs
if accountAndChainIDs.Address == gethcommon.HexToAddress(request.AddressesToReveal[i]) {
revealedAcc.ChainIds = accountAndChainIDs.ChainIDs
break
}
}
for _, revealedAccount := range revealedAccounts {
requestToEditRevealedAccountsProto.RevealedAccounts = append(requestToEditRevealedAccountsProto.RevealedAccounts, revealedAccount)
requestToEditRevealedAccountsProto.RevealedAccounts = append(requestToEditRevealedAccountsProto.RevealedAccounts, revealedAcc)
}
requestID := communities.CalculateRequestID(common.PubkeyToHex(&m.identity.PublicKey), request.CommunityID)

View File

@ -74,10 +74,10 @@ func (s *MessengerDeleteMessageForEveryoneSuite) TestDeleteMessageForEveryone()
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
advertiseCommunityTo(&s.Suite, community, s.admin, s.moderator)
joinCommunity(&s.Suite, community, s.admin, s.moderator, request)
joinCommunity(&s.Suite, community, s.admin, s.moderator, request, "")
advertiseCommunityTo(&s.Suite, community, s.admin, s.bob)
joinCommunity(&s.Suite, community, s.admin, s.bob, request)
joinCommunity(&s.Suite, community, s.admin, s.bob, request, "")
response, err := s.admin.AddRoleToMember(&requests.AddRoleToMember{
CommunityID: community.ID(),

View File

@ -69,7 +69,7 @@ func (s *MessengerSendImagesAlbumSuite) advertiseCommunityTo(community *communit
func (s *MessengerSendImagesAlbumSuite) joinCommunity(community *communities.Community, user *Messenger) {
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
joinCommunity(&s.Suite, community, s.m, user, request)
joinCommunity(&s.Suite, community, s.m, user, request, "")
}
func (s *MessengerSendImagesAlbumSuite) TestAlbumImageMessagesSend() {

View File

@ -3,6 +3,7 @@ package requests
import (
"errors"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
)
@ -10,11 +11,13 @@ var ErrInvalidCommunityID = errors.New("invalid community id")
var ErrMissingPassword = errors.New("password is necessary when sending a list of addresses")
var ErrMissingSharedAddresses = errors.New("list of shared addresses is needed")
var ErrMissingAirdropAddress = errors.New("airdropAddress is needed")
var ErrNoAirdropAddressAmongAddressesToReveal = errors.New("airdropAddress must be in the set of addresses to reveal")
var ErrInvalidSignature = errors.New("invalid signature")
type EditSharedAddresses struct {
CommunityID types.HexBytes `json:"communityId"`
Password string `json:"password"`
AddressesToReveal []string `json:"addressesToReveal"`
Signatures []types.HexBytes `json:"signatures"` // the order of signatures should match the order of addresses
AirdropAddress string `json:"airdropAddress"`
}
@ -22,15 +25,32 @@ func (j *EditSharedAddresses) Validate() error {
if len(j.CommunityID) == 0 {
return ErrInvalidCommunityID
}
if j.Password == "" {
return ErrMissingPassword
}
if len(j.AddressesToReveal) == 0 {
return ErrMissingSharedAddresses
}
if j.AirdropAddress == "" {
return ErrMissingAirdropAddress
}
found := false
for _, address := range j.AddressesToReveal {
if address == j.AirdropAddress {
found = true
break
}
}
if !found {
return ErrNoAirdropAddressAmongAddressesToReveal
}
for _, signature := range j.Signatures {
if len(signature) > 0 && len(signature) != crypto.SignatureLength {
return ErrInvalidSignature
}
}
return nil
}

View File

@ -3,31 +3,63 @@ package requests
import (
"errors"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
)
var ErrRequestToJoinCommunityInvalidCommunityID = errors.New("request-to-join-community: invalid community id")
var ErrRequestToJoinCommunityNoAddressesToReveal = errors.New("request-to-join-community: no addresses to reveal")
var ErrRequestToJoinCommunityMissingPassword = errors.New("request-to-join-community: password is necessary when sending a list of addresses")
var ErrRequestToJoinNoAirdropAddress = errors.New("request-to-join-community: airdropAddress is necessary when sending a list of addresses")
var ErrRequestToJoinNoAirdropAddressAmongAddressesToReveal = errors.New("request-to-join-community: airdropAddress must be in the set of addresses to reveal")
var ErrRequestToJoinCommunityInvalidSignature = errors.New("request-to-join-community: invalid signature")
type RequestToJoinCommunity struct {
CommunityID types.HexBytes `json:"communityId"`
ENSName string `json:"ensName"`
Password string `json:"password"`
AddressesToReveal []string `json:"addressesToReveal"`
Signatures []types.HexBytes `json:"signatures"` // the order of signatures should match the order of addresses
AirdropAddress string `json:"airdropAddress"`
}
func (j *RequestToJoinCommunity) Validate() error {
func (j *RequestToJoinCommunity) Validate(full bool) error {
// TODO: A parital validation, in case `full` is set to `false` should check `AddressesToReveal` as well. But because of changes
// that need to be done in tests we cannot do that now.
// Also in the line 61, we should remove `len(signature) > 0` from the condition, but from the same reason we cannot do that now.
if len(j.CommunityID) == 0 {
return ErrRequestToJoinCommunityInvalidCommunityID
}
if len(j.AddressesToReveal) > 0 && j.Password == "" {
return ErrRequestToJoinCommunityMissingPassword
if !full {
return nil
}
if len(j.AddressesToReveal) > 0 && j.AirdropAddress == "" {
if len(j.AddressesToReveal) == 0 {
return ErrRequestToJoinCommunityNoAddressesToReveal
}
if j.AirdropAddress == "" {
return ErrRequestToJoinNoAirdropAddress
}
found := false
for _, address := range j.AddressesToReveal {
if address == j.AirdropAddress {
found = true
break
}
}
if !found {
return ErrRequestToJoinNoAirdropAddressAmongAddressesToReveal
}
for _, signature := range j.Signatures {
if len(signature) > 0 && len(signature) != crypto.SignatureLength {
return ErrRequestToJoinCommunityInvalidSignature
}
}
return nil
}

View File

@ -9,6 +9,7 @@ import (
"math/big"
"time"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/services/browsers"
"github.com/status-im/status-go/services/wallet"
"github.com/status-im/status-go/services/wallet/bigint"
@ -586,6 +587,27 @@ func (api *PublicAPI) CanceledRequestsToJoinForCommunity(id types.HexBytes) ([]*
return api.service.messenger.CanceledRequestsToJoinForCommunity(id)
}
// Generates a single hash for each address that needs to be revealed to a community.
// Each hash needs to be signed.
// The order of retuned hashes corresponds to the order of addresses in addressesToReveal.
func (api *PublicAPI) GenerateJoiningCommunityRequestsForSigning(memberPubKey string, communityID types.HexBytes, addressesToReveal []string) ([]account.SignParams, error) {
return api.service.messenger.GenerateJoiningCommunityRequestsForSigning(memberPubKey, communityID, addressesToReveal)
}
// Generates a single hash for each address that needs to be revealed to a community.
// Each hash needs to be signed.
// The order of retuned hashes corresponds to the order of addresses in addressesToReveal.
func (api *PublicAPI) GenerateEditCommunityRequestsForSigning(memberPubKey string, communityID types.HexBytes, addressesToReveal []string) ([]account.SignParams, error) {
return api.service.messenger.GenerateEditCommunityRequestsForSigning(memberPubKey, communityID, addressesToReveal)
}
// Signs the provided messages with the provided accounts and password.
// Provided accounts must not belong to a keypair that is migrated to a keycard.
// Otherwise, the signing will fail, cause such accounts should be signed with a keycard.
func (api *PublicAPI) SignData(signParams []account.SignParams) ([]string, error) {
return api.service.messenger.SignData(signParams)
}
// CancelRequestToJoinCommunity accepts a pending request to join a community
func (api *PublicAPI) CancelRequestToJoinCommunity(ctx context.Context, request *requests.CancelRequestToJoinCommunity) (*protocol.MessengerResponse, error) {
return api.service.messenger.CancelRequestToJoinCommunity(ctx, request)