feat: support signing of a join/edit community request from within the app or keycard
This commit is contained in:
parent
cb3a88f93a
commit
11a3612290
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
revealedAccounts[revealedAddress] = &protobuf.RevealedAccount{
|
||||
Address: address,
|
||||
IsAirdropAddress: isAirdropAddress,
|
||||
Signature: signatureBytes,
|
||||
ChainIds: make([]uint64, 0),
|
||||
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(),
|
||||
})
|
||||
}
|
||||
return revealedAccounts, revealedAddresses, nil
|
||||
|
||||
return msgsToSign, nil
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
for _, accountAndChainIDs := range checkPermissionResponse.ValidCombinations {
|
||||
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)
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,27 +11,46 @@ 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"`
|
||||
AirdropAddress string `json:"airdropAddress"`
|
||||
CommunityID types.HexBytes `json:"communityId"`
|
||||
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 *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
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
AirdropAddress string `json:"airdropAddress"`
|
||||
CommunityID types.HexBytes `json:"communityId"`
|
||||
ENSName string `json:"ensName"`
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue