2020-12-22 10:49:25 +00:00
|
|
|
package protocol
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/ecdsa"
|
2022-01-18 16:31:34 +00:00
|
|
|
"errors"
|
2023-06-08 12:00:19 +00:00
|
|
|
"fmt"
|
2020-12-22 10:49:25 +00:00
|
|
|
|
|
|
|
"github.com/golang/protobuf/proto"
|
2022-06-13 10:57:51 +00:00
|
|
|
"go.uber.org/zap"
|
2020-12-22 10:49:25 +00:00
|
|
|
|
2023-08-03 14:16:11 +00:00
|
|
|
"github.com/status-im/status-go/deprecation"
|
2023-06-08 12:00:19 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
2022-01-18 16:31:34 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
test_: Code Migration from status-cli-tests
author shashankshampi <shashank.sanket1995@gmail.com> 1729780155 +0530
committer shashankshampi <shashank.sanket1995@gmail.com> 1730274350 +0530
test: Code Migration from status-cli-tests
fix_: functional tests (#5979)
* fix_: generate on test-functional
* chore(test)_: fix functional test assertion
---------
Co-authored-by: Siddarth Kumar <siddarthkay@gmail.com>
feat(accounts)_: cherry-pick Persist acceptance of Terms of Use & Privacy policy (#5766) (#5977)
* feat(accounts)_: Persist acceptance of Terms of Use & Privacy policy (#5766)
The original GH issue https://github.com/status-im/status-mobile/issues/21113
came from a request from the Legal team. We must show to Status v1 users the new
terms (Terms of Use & Privacy Policy) right after they upgrade to Status v2
from the stores.
The solution we use is to create a flag in the accounts table, named
hasAcceptedTerms. The flag will be set to true on the first account ever
created in v2 and we provide a native call in mobile/status.go#AcceptTerms,
which allows the client to persist the user's choice in case they are upgrading
(from v1 -> v2, or from a v2 older than this PR).
This solution is not the best because we should store the setting in a separate
table, not in the accounts table.
Related Mobile PR https://github.com/status-im/status-mobile/pull/21124
* fix(test)_: Compare addresses using uppercased strings
---------
Co-authored-by: Icaro Motta <icaro.ldm@gmail.com>
test_: restore account (#5960)
feat_: `LogOnPanic` linter (#5969)
* feat_: LogOnPanic linter
* fix_: add missing defer LogOnPanic
* chore_: make vendor
* fix_: tests, address pr comments
* fix_: address pr comments
fix(ci)_: remove workspace and tmp dir
This ensures we do not encounter weird errors like:
```
+ ln -s /home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907 /home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907@tmp/go/src/github.com/status-im/status-go
ln: failed to create symbolic link '/home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907@tmp/go/src/github.com/status-im/status-go': File exists
script returned exit code 1
```
Signed-off-by: Jakub Sokołowski <jakub@status.im>
chore_: enable windows and macos CI build (#5840)
- Added support for Windows and macOS in CI pipelines
- Added missing dependencies for Windows and x86-64-darwin
- Resolved macOS SDK version compatibility for darwin-x86_64
The `mkShell` override was necessary to ensure compatibility with the newer
macOS SDK (version 11.0) for x86_64. The default SDK (10.12) was causing build failures
because of the missing libs and frameworks. OverrideSDK creates a mapping from
the default SDK in all package categories to the requested SDK (11.0).
fix(contacts)_: fix trust status not being saved to cache when changed (#5965)
Fixes https://github.com/status-im/status-desktop/issues/16392
cleanup
added logger and cleanup
review comments changes
fix_: functional tests (#5979)
* fix_: generate on test-functional
* chore(test)_: fix functional test assertion
---------
Co-authored-by: Siddarth Kumar <siddarthkay@gmail.com>
feat(accounts)_: cherry-pick Persist acceptance of Terms of Use & Privacy policy (#5766) (#5977)
* feat(accounts)_: Persist acceptance of Terms of Use & Privacy policy (#5766)
The original GH issue https://github.com/status-im/status-mobile/issues/21113
came from a request from the Legal team. We must show to Status v1 users the new
terms (Terms of Use & Privacy Policy) right after they upgrade to Status v2
from the stores.
The solution we use is to create a flag in the accounts table, named
hasAcceptedTerms. The flag will be set to true on the first account ever
created in v2 and we provide a native call in mobile/status.go#AcceptTerms,
which allows the client to persist the user's choice in case they are upgrading
(from v1 -> v2, or from a v2 older than this PR).
This solution is not the best because we should store the setting in a separate
table, not in the accounts table.
Related Mobile PR https://github.com/status-im/status-mobile/pull/21124
* fix(test)_: Compare addresses using uppercased strings
---------
Co-authored-by: Icaro Motta <icaro.ldm@gmail.com>
test_: restore account (#5960)
feat_: `LogOnPanic` linter (#5969)
* feat_: LogOnPanic linter
* fix_: add missing defer LogOnPanic
* chore_: make vendor
* fix_: tests, address pr comments
* fix_: address pr comments
chore_: enable windows and macos CI build (#5840)
- Added support for Windows and macOS in CI pipelines
- Added missing dependencies for Windows and x86-64-darwin
- Resolved macOS SDK version compatibility for darwin-x86_64
The `mkShell` override was necessary to ensure compatibility with the newer
macOS SDK (version 11.0) for x86_64. The default SDK (10.12) was causing build failures
because of the missing libs and frameworks. OverrideSDK creates a mapping from
the default SDK in all package categories to the requested SDK (11.0).
fix(contacts)_: fix trust status not being saved to cache when changed (#5965)
Fixes https://github.com/status-im/status-desktop/issues/16392
test_: remove port bind
chore(wallet)_: move route execution code to separate module
chore_: replace geth logger with zap logger (#5962)
closes: #6002
feat(telemetry)_: add metrics for message reliability (#5899)
* feat(telemetry)_: track message reliability
Add metrics for dial errors, missed messages,
missed relevant messages, and confirmed delivery.
* fix_: handle error from json marshal
chore_: use zap logger as request logger
iterates: status-im/status-desktop#16536
test_: unique project per run
test_: use docker compose v2, more concrete project name
fix(codecov)_: ignore folders without tests
Otherwise Codecov reports incorrect numbers when making changes.
https://docs.codecov.com/docs/ignoring-paths
Signed-off-by: Jakub Sokołowski <jakub@status.im>
test_: verify schema of signals during init; fix schema verification warnings (#5947)
fix_: update defaultGorushURL (#6011)
fix(tests)_: use non-standard port to avoid conflicts
We have observed `nimbus-eth2` build failures reporting this port:
```json
{
"lvl": "NTC",
"ts": "2024-10-28 13:51:32.308+00:00",
"msg": "REST HTTP server could not be started",
"topics": "beacnde",
"address": "127.0.0.1:5432",
"reason": "(98) Address already in use"
}
```
https://ci.status.im/job/nimbus-eth2/job/platforms/job/linux/job/x86_64/job/main/job/PR-6683/3/
Signed-off-by: Jakub Sokołowski <jakub@status.im>
fix_: create request logger ad-hoc in tests
Fixes `TestCall` failing when run concurrently.
chore_: configure codecov (#6005)
* chore_: configure codecov
* fix_: after_n_builds
2024-10-24 14:29:15 +00:00
|
|
|
"github.com/status-im/status-go/logutils"
|
2024-04-03 14:49:57 +00:00
|
|
|
multiaccountscommon "github.com/status-im/status-go/multiaccounts/common"
|
2020-12-22 10:49:25 +00:00
|
|
|
"github.com/status-im/status-go/protocol/common"
|
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
2021-10-25 10:25:37 +00:00
|
|
|
"github.com/status-im/status-go/protocol/requests"
|
2021-02-17 23:14:48 +00:00
|
|
|
"github.com/status-im/status-go/protocol/transport"
|
2020-12-22 10:49:25 +00:00
|
|
|
)
|
|
|
|
|
2023-07-12 15:12:58 +00:00
|
|
|
const outgoingMutualStateEventSentDefaultText = "You sent a contact request to @%s"
|
|
|
|
const outgoingMutualStateEventAcceptedDefaultText = "You accepted @%s's contact request"
|
|
|
|
const outgoingMutualStateEventRemovedDefaultText = "You removed @%s as a contact"
|
|
|
|
const incomingMutualStateEventSentDefaultText = "@%s sent you a contact request"
|
|
|
|
const incomingMutualStateEventAcceptedDefaultText = "@%s accepted your contact request"
|
|
|
|
const incomingMutualStateEventRemovedDefaultText = "@%s removed you as a contact"
|
|
|
|
|
2024-02-28 20:00:35 +00:00
|
|
|
var ErrGetLatestContactRequestForContactInvalidID = errors.New("get-latest-contact-request-for-contact: invalid id")
|
|
|
|
|
2023-11-13 20:07:35 +00:00
|
|
|
type SelfContactChangeEvent struct {
|
|
|
|
DisplayNameChanged bool
|
|
|
|
PreferredNameChanged bool
|
|
|
|
BioChanged bool
|
|
|
|
SocialLinksChanged bool
|
|
|
|
ImagesChanged bool
|
|
|
|
}
|
|
|
|
|
2023-06-08 12:00:19 +00:00
|
|
|
func (m *Messenger) prepareMutualStateUpdateMessage(contactID string, updateType MutualStateUpdateType, clock uint64, timestamp uint64, outgoing bool) (*common.Message, error) {
|
|
|
|
var text string
|
|
|
|
var to string
|
|
|
|
var from string
|
2023-07-12 15:12:58 +00:00
|
|
|
var contentType protobuf.ChatMessage_ContentType
|
2023-06-08 12:00:19 +00:00
|
|
|
if outgoing {
|
|
|
|
to = contactID
|
|
|
|
from = m.myHexIdentity()
|
|
|
|
|
|
|
|
switch updateType {
|
|
|
|
case MutualStateUpdateTypeSent:
|
2023-07-12 15:12:58 +00:00
|
|
|
text = fmt.Sprintf(outgoingMutualStateEventSentDefaultText, contactID)
|
|
|
|
contentType = protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_SENT
|
2023-06-08 12:00:19 +00:00
|
|
|
case MutualStateUpdateTypeAdded:
|
2023-07-12 15:12:58 +00:00
|
|
|
text = fmt.Sprintf(outgoingMutualStateEventAcceptedDefaultText, contactID)
|
|
|
|
contentType = protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED
|
2023-06-08 12:00:19 +00:00
|
|
|
case MutualStateUpdateTypeRemoved:
|
2023-07-12 15:12:58 +00:00
|
|
|
text = fmt.Sprintf(outgoingMutualStateEventRemovedDefaultText, contactID)
|
|
|
|
contentType = protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED
|
2023-06-08 12:00:19 +00:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unhandled outgoing MutualStateUpdateType = %d", updateType)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
to = m.myHexIdentity()
|
|
|
|
from = contactID
|
|
|
|
|
|
|
|
switch updateType {
|
|
|
|
case MutualStateUpdateTypeSent:
|
2023-07-12 15:12:58 +00:00
|
|
|
text = fmt.Sprintf(incomingMutualStateEventSentDefaultText, contactID)
|
|
|
|
contentType = protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_SENT
|
2023-06-08 12:00:19 +00:00
|
|
|
case MutualStateUpdateTypeAdded:
|
2023-07-12 15:12:58 +00:00
|
|
|
text = fmt.Sprintf(incomingMutualStateEventAcceptedDefaultText, contactID)
|
|
|
|
contentType = protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED
|
2023-06-08 12:00:19 +00:00
|
|
|
case MutualStateUpdateTypeRemoved:
|
2023-07-12 15:12:58 +00:00
|
|
|
text = fmt.Sprintf(incomingMutualStateEventRemovedDefaultText, contactID)
|
|
|
|
contentType = protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED
|
2023-06-08 12:00:19 +00:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unhandled incoming MutualStateUpdateType = %d", updateType)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
message := &common.Message{
|
2023-08-18 11:39:59 +00:00
|
|
|
ChatMessage: &protobuf.ChatMessage{
|
2023-06-08 12:00:19 +00:00
|
|
|
ChatId: contactID,
|
|
|
|
Text: text,
|
|
|
|
MessageType: protobuf.MessageType_ONE_TO_ONE,
|
2023-07-12 15:12:58 +00:00
|
|
|
ContentType: contentType,
|
2023-06-08 12:00:19 +00:00
|
|
|
Clock: clock,
|
|
|
|
Timestamp: timestamp,
|
|
|
|
},
|
|
|
|
From: from,
|
|
|
|
WhisperTimestamp: timestamp,
|
|
|
|
LocalChatID: contactID,
|
2023-07-25 08:35:05 +00:00
|
|
|
Seen: true,
|
2023-06-08 12:00:19 +00:00
|
|
|
ID: types.EncodeHex(crypto.Keccak256([]byte(fmt.Sprintf("%s%s%d%d", from, to, updateType, clock)))),
|
|
|
|
}
|
|
|
|
|
|
|
|
return message, nil
|
|
|
|
}
|
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
func (m *Messenger) acceptContactRequest(ctx context.Context, requestID string, fromSyncing bool) (*MessengerResponse, error) {
|
2022-08-07 14:25:03 +00:00
|
|
|
contactRequest, err := m.persistence.MessageByID(requestID)
|
|
|
|
if err != nil {
|
|
|
|
m.logger.Error("could not find contact request message", zap.Error(err))
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
m.logger.Info("acceptContactRequest")
|
2023-04-25 11:27:15 +00:00
|
|
|
|
2024-04-03 14:49:57 +00:00
|
|
|
var ensName, nickname, displayName string
|
|
|
|
customizationColor := multiaccountscommon.IDToColorFallbackToBlue(contactRequest.CustomizationColor)
|
|
|
|
|
|
|
|
if contact, ok := m.allContacts.Load(contactRequest.From); ok {
|
|
|
|
ensName = contact.EnsName
|
|
|
|
nickname = contact.LocalNickname
|
|
|
|
displayName = contact.DisplayName
|
|
|
|
customizationColor = contact.CustomizationColor
|
|
|
|
}
|
|
|
|
|
|
|
|
response, err := m.addContact(ctx, contactRequest.From, ensName, nickname, displayName, customizationColor, contactRequest.ID, "", fromSyncing, false, false)
|
2023-04-25 11:27:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force activate chat
|
|
|
|
chat, ok := m.allChats.Load(contactRequest.From)
|
|
|
|
if !ok {
|
|
|
|
publicKey, err := common.HexToPubkey(contactRequest.From)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
chat = OneToOneFromPublicKey(publicKey, m.getTimesource())
|
|
|
|
}
|
|
|
|
|
|
|
|
chat.Active = true
|
|
|
|
if err := m.saveChat(chat); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
response.AddChat(chat)
|
|
|
|
|
|
|
|
return response, nil
|
2022-08-07 14:25:03 +00:00
|
|
|
}
|
|
|
|
|
2022-01-18 16:31:34 +00:00
|
|
|
func (m *Messenger) AcceptContactRequest(ctx context.Context, request *requests.AcceptContactRequest) (*MessengerResponse, error) {
|
|
|
|
err := request.Validate()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-04-25 11:27:15 +00:00
|
|
|
response, err := m.acceptContactRequest(ctx, request.ID.String(), false)
|
2022-01-18 16:31:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-05-15 00:01:47 +00:00
|
|
|
err = m.syncContactRequestDecision(ctx, request.ID.String(), "", true, m.dispatchMessage)
|
2022-08-07 14:25:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return response, nil
|
2022-01-18 16:31:34 +00:00
|
|
|
}
|
|
|
|
|
2024-05-15 00:01:47 +00:00
|
|
|
func (m *Messenger) declineContactRequest(requestID, contactID string, fromSyncing bool) (*MessengerResponse, error) {
|
2023-02-21 18:08:11 +00:00
|
|
|
m.logger.Info("declineContactRequest")
|
2024-05-15 00:01:47 +00:00
|
|
|
|
2023-02-21 18:08:11 +00:00
|
|
|
contactRequest, err := m.persistence.MessageByID(requestID)
|
2024-05-15 00:01:47 +00:00
|
|
|
if err == common.ErrRecordNotFound && fromSyncing {
|
|
|
|
// original requestID(Message ID) is useless since we don't sync UserMessage in this case
|
|
|
|
requestID = defaultContactRequestID(contactID)
|
|
|
|
contactRequest, err = m.persistence.MessageByID(requestID)
|
2022-01-18 16:31:34 +00:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-21 18:08:11 +00:00
|
|
|
response := &MessengerResponse{}
|
2024-05-15 00:01:47 +00:00
|
|
|
var contact *Contact
|
|
|
|
if contactRequest != nil {
|
|
|
|
contact, err = m.BuildContact(&requests.BuildContact{PublicKey: contactRequest.From})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
contactRequest.ContactRequestState = common.ContactRequestStateDismissed
|
|
|
|
err = m.persistence.SetContactRequestState(contactRequest.ID, contactRequest.ContactRequestState)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
response.AddMessage(contactRequest)
|
|
|
|
}
|
2022-01-18 16:31:34 +00:00
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
if !fromSyncing {
|
2023-02-21 18:08:11 +00:00
|
|
|
_, clock, err := m.getOneToOneAndNextClock(contact)
|
2022-01-18 16:31:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-02-21 18:08:11 +00:00
|
|
|
|
|
|
|
contact.DismissContactRequest(clock)
|
|
|
|
err = m.persistence.SaveContact(contact, nil)
|
2022-01-18 16:31:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-21 18:08:11 +00:00
|
|
|
response.AddContact(contact)
|
|
|
|
}
|
2022-01-18 16:31:34 +00:00
|
|
|
|
2023-02-21 18:08:11 +00:00
|
|
|
// update notification with the correct status
|
2024-05-15 00:01:47 +00:00
|
|
|
notification, err := m.persistence.GetActivityCenterNotificationByID(types.FromHex(requestID))
|
2022-01-18 16:31:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-02-21 18:08:11 +00:00
|
|
|
if notification != nil {
|
2023-04-25 11:27:15 +00:00
|
|
|
notification.Name = contact.PrimaryName()
|
2023-02-21 18:08:11 +00:00
|
|
|
notification.Message = contactRequest
|
|
|
|
notification.Read = true
|
|
|
|
notification.Dismissed = true
|
2023-10-22 09:41:20 +00:00
|
|
|
notification.UpdatedAt = m.GetCurrentTimeInMillis()
|
2022-01-18 16:31:34 +00:00
|
|
|
|
2023-10-22 09:41:20 +00:00
|
|
|
err = m.addActivityCenterNotification(response, notification, m.syncActivityCenterDismissedByIDs)
|
2023-02-21 18:08:11 +00:00
|
|
|
if err != nil {
|
|
|
|
m.logger.Error("failed to save notification", zap.Error(err))
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2022-01-18 16:31:34 +00:00
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
2023-02-21 18:08:11 +00:00
|
|
|
func (m *Messenger) DeclineContactRequest(ctx context.Context, request *requests.DeclineContactRequest) (*MessengerResponse, error) {
|
|
|
|
err := request.Validate()
|
2021-11-22 17:21:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-05-15 00:01:47 +00:00
|
|
|
response, err := m.declineContactRequest(request.ID.String(), "", false)
|
2021-11-22 17:21:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-05-15 00:01:47 +00:00
|
|
|
err = m.syncContactRequestDecision(ctx, request.ID.String(), "", false, m.dispatchMessage)
|
2023-02-21 18:08:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Messenger) SendContactRequest(ctx context.Context, request *requests.SendContactRequest) (*MessengerResponse, error) {
|
2022-08-07 14:25:03 +00:00
|
|
|
err := request.Validate()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-10-14 08:50:36 +00:00
|
|
|
chatID, err := request.HexID()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-02-21 18:08:11 +00:00
|
|
|
|
2024-04-03 14:49:57 +00:00
|
|
|
var ensName, nickname, displayName string
|
|
|
|
customizationColor := multiaccountscommon.CustomizationColorBlue
|
|
|
|
|
|
|
|
if contact, ok := m.allContacts.Load(chatID); ok {
|
|
|
|
ensName = contact.EnsName
|
|
|
|
nickname = contact.LocalNickname
|
|
|
|
displayName = contact.DisplayName
|
|
|
|
customizationColor = contact.CustomizationColor
|
|
|
|
}
|
|
|
|
|
2023-04-25 11:27:15 +00:00
|
|
|
return m.addContact(
|
|
|
|
ctx,
|
2023-02-21 18:08:11 +00:00
|
|
|
chatID,
|
2024-04-03 14:49:57 +00:00
|
|
|
ensName,
|
|
|
|
nickname,
|
|
|
|
displayName,
|
|
|
|
customizationColor,
|
2023-02-21 18:08:11 +00:00
|
|
|
"",
|
|
|
|
request.Message,
|
|
|
|
false,
|
|
|
|
false,
|
2023-04-25 11:27:15 +00:00
|
|
|
true,
|
2023-02-21 18:08:11 +00:00
|
|
|
)
|
2022-08-07 14:25:03 +00:00
|
|
|
}
|
|
|
|
|
2024-05-15 00:01:47 +00:00
|
|
|
func (m *Messenger) updateAcceptedContactRequest(response *MessengerResponse, contactRequestID, contactID string, fromSyncing bool) (*MessengerResponse, error) {
|
|
|
|
m.logger.Debug("updateAcceptedContactRequest", zap.String("contactRequestID", contactRequestID), zap.String("contactID", contactID), zap.Bool("fromSyncing", fromSyncing))
|
2023-07-12 09:46:56 +00:00
|
|
|
|
2022-08-07 14:25:03 +00:00
|
|
|
contactRequest, err := m.persistence.MessageByID(contactRequestID)
|
2024-05-15 00:01:47 +00:00
|
|
|
if err == common.ErrRecordNotFound && fromSyncing {
|
|
|
|
// original requestID(Message ID) is useless since we don't sync UserMessage in this case
|
|
|
|
contactRequestID = defaultContactRequestID(contactID)
|
|
|
|
contactRequest, err = m.persistence.MessageByID(contactRequestID)
|
|
|
|
}
|
2022-08-07 14:25:03 +00:00
|
|
|
if err != nil {
|
2023-07-12 09:46:56 +00:00
|
|
|
m.logger.Error("contact request not found", zap.String("contactRequestID", contactRequestID), zap.Error(err))
|
2022-08-07 14:25:03 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
contactRequest.ContactRequestState = common.ContactRequestStateAccepted
|
2021-10-29 15:18:21 +00:00
|
|
|
|
2022-01-18 16:31:34 +00:00
|
|
|
err = m.persistence.SetContactRequestState(contactRequest.ID, contactRequest.ContactRequestState)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-07-12 09:46:56 +00:00
|
|
|
contact, ok := m.allContacts.Load(contactRequest.From)
|
|
|
|
if !ok {
|
|
|
|
m.logger.Error("failed to update contact request: contact not found", zap.String("contact id", contactRequest.From))
|
|
|
|
return nil, errors.New("failed to update contact request: contact not found")
|
|
|
|
}
|
2022-08-07 14:25:03 +00:00
|
|
|
|
2023-07-12 15:12:58 +00:00
|
|
|
chat, ok := m.allChats.Load(contact.ID)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("no chat found for accepted contact request")
|
|
|
|
}
|
|
|
|
|
|
|
|
notification, err := m.persistence.GetActivityCenterNotificationByID(types.FromHex(contactRequest.ID))
|
2023-01-20 14:28:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2022-08-07 14:25:03 +00:00
|
|
|
}
|
2023-01-20 14:28:30 +00:00
|
|
|
|
2023-07-12 15:12:58 +00:00
|
|
|
clock, _ := chat.NextClockAndTimestamp(m.transport)
|
2023-01-20 14:28:30 +00:00
|
|
|
contact.AcceptContactRequest(clock)
|
|
|
|
|
2023-12-05 04:22:20 +00:00
|
|
|
if !fromSyncing {
|
|
|
|
acceptContactRequest := &protobuf.AcceptContactRequest{
|
|
|
|
Id: contactRequest.ID,
|
|
|
|
Clock: clock,
|
|
|
|
}
|
|
|
|
encodedMessage, err := proto.Marshal(acceptContactRequest)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_, err = m.dispatchMessage(context.Background(), common.RawMessage{
|
2024-03-22 10:55:09 +00:00
|
|
|
LocalChatID: contactRequest.From,
|
|
|
|
Payload: encodedMessage,
|
|
|
|
MessageType: protobuf.ApplicationMetadataMessage_ACCEPT_CONTACT_REQUEST,
|
|
|
|
ResendType: common.ResendTypeDataSync,
|
2023-12-05 04:22:20 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-02-09 09:36:54 +00:00
|
|
|
|
|
|
|
// Dispatch profile message to add a contact to the encrypted profile part
|
|
|
|
err = m.DispatchProfileShowcase()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-08-07 14:25:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if response == nil {
|
|
|
|
response = &MessengerResponse{}
|
|
|
|
}
|
|
|
|
|
2022-01-18 16:31:34 +00:00
|
|
|
if notification != nil {
|
2023-04-25 11:27:15 +00:00
|
|
|
notification.Name = contact.PrimaryName()
|
2023-01-28 09:52:53 +00:00
|
|
|
notification.Message = contactRequest
|
|
|
|
notification.Read = true
|
|
|
|
notification.Accepted = true
|
2023-10-22 09:41:20 +00:00
|
|
|
notification.UpdatedAt = m.GetCurrentTimeInMillis()
|
2023-01-28 09:52:53 +00:00
|
|
|
|
2023-10-22 09:41:20 +00:00
|
|
|
err = m.addActivityCenterNotification(response, notification, nil)
|
2022-01-18 16:31:34 +00:00
|
|
|
if err != nil {
|
2023-01-28 09:52:53 +00:00
|
|
|
m.logger.Error("failed to save notification", zap.Error(err))
|
2022-01-18 16:31:34 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
response.AddMessage(contactRequest)
|
2023-01-20 14:28:30 +00:00
|
|
|
response.AddContact(contact)
|
2022-01-18 16:31:34 +00:00
|
|
|
|
2023-07-12 15:12:58 +00:00
|
|
|
// Add mutual state update message for incoming contact request
|
|
|
|
clock, timestamp := chat.NextClockAndTimestamp(m.transport)
|
|
|
|
updateMessage, err := m.prepareMutualStateUpdateMessage(contact.ID, MutualStateUpdateTypeAdded, clock, timestamp, true)
|
2023-06-08 12:00:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-01-08 18:18:57 +00:00
|
|
|
err = m.prepareMessage(updateMessage, m.httpServer)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-06-08 12:00:19 +00:00
|
|
|
err = m.persistence.SaveMessages([]*common.Message{updateMessage})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
response.AddMessage(updateMessage)
|
|
|
|
response.AddChat(chat)
|
|
|
|
|
2022-01-18 16:31:34 +00:00
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
2024-04-03 14:49:57 +00:00
|
|
|
func (m *Messenger) addContact(ctx context.Context,
|
|
|
|
pubKey, ensName, nickname, displayName string,
|
|
|
|
customizationColor multiaccountscommon.CustomizationColor,
|
|
|
|
contactRequestID, contactRequestText string,
|
|
|
|
fromSyncing, sendContactUpdate, createOutgoingContactRequestNotification bool) (*MessengerResponse, error) {
|
2023-03-14 15:34:35 +00:00
|
|
|
contact, err := m.BuildContact(&requests.BuildContact{PublicKey: pubKey})
|
2023-01-20 14:28:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-07-12 15:12:58 +00:00
|
|
|
response := &MessengerResponse{}
|
|
|
|
|
|
|
|
chat, clock, err := m.getOneToOneAndNextClock(contact)
|
2023-01-20 14:28:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2021-10-29 15:18:21 +00:00
|
|
|
if ensName != "" {
|
|
|
|
err := m.ensVerifier.ENSVerified(pubKey, ensName, clock)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2021-10-26 10:48:02 +00:00
|
|
|
if err := m.addENSNameToContact(contact); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-01-18 16:31:34 +00:00
|
|
|
if len(nickname) != 0 {
|
|
|
|
contact.LocalNickname = nickname
|
2021-10-25 10:25:37 +00:00
|
|
|
}
|
|
|
|
|
2022-01-18 16:31:34 +00:00
|
|
|
if len(displayName) != 0 {
|
|
|
|
contact.DisplayName = displayName
|
2022-02-17 15:13:10 +00:00
|
|
|
}
|
|
|
|
|
2024-04-03 14:49:57 +00:00
|
|
|
contact.CustomizationColor = customizationColor
|
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
contact.LastUpdatedLocally = clock
|
|
|
|
contact.ContactRequestSent(clock)
|
2022-01-18 16:31:34 +00:00
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
if !fromSyncing {
|
2022-08-07 14:25:03 +00:00
|
|
|
// We sync the contact with the other devices
|
2023-01-06 12:21:14 +00:00
|
|
|
err := m.syncContact(context.Background(), contact, m.dispatchMessage)
|
2022-08-07 14:25:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
err = m.persistence.SaveContact(contact, nil)
|
2020-12-22 10:49:25 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:41:30 +00:00
|
|
|
// TODO(samyoul) remove storing of an updated reference pointer?
|
|
|
|
m.allContacts.Store(contact.ID, contact)
|
2020-12-22 10:49:25 +00:00
|
|
|
|
|
|
|
// And we re-register for push notications
|
|
|
|
err = m.reregisterForPushNotifications()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-02-17 23:14:48 +00:00
|
|
|
// Reset last published time for ChatIdentity so new contact can receive data
|
2021-10-07 15:02:01 +00:00
|
|
|
err = m.resetLastPublishedTimeForChatIdentity()
|
2021-02-17 23:14:48 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-08-03 14:16:11 +00:00
|
|
|
// Profile chats are deprecated.
|
|
|
|
// Code below can be removed after some reasonable time.
|
2020-12-22 10:49:25 +00:00
|
|
|
|
2023-08-03 14:16:11 +00:00
|
|
|
//Create the corresponding chat
|
|
|
|
var profileChat *Chat
|
|
|
|
if !deprecation.ChatProfileDeprecated {
|
|
|
|
profileChat = m.buildProfileChat(contact.ID)
|
2023-04-25 11:27:15 +00:00
|
|
|
|
2023-08-03 14:16:11 +00:00
|
|
|
_, err = m.Join(profileChat)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := m.saveChat(profileChat); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-11-03 11:31:11 +00:00
|
|
|
}
|
2020-12-22 10:49:25 +00:00
|
|
|
|
2021-10-22 14:20:42 +00:00
|
|
|
publicKey, err := contact.PublicKey()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-04-05 20:25:44 +00:00
|
|
|
|
|
|
|
// Fetch contact code
|
|
|
|
_, err = m.scheduleSyncFiltersForContact(publicKey)
|
2022-01-31 10:33:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-10-22 14:20:42 +00:00
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
if sendContactUpdate {
|
2024-04-03 14:49:57 +00:00
|
|
|
// Get ENS name of a current user
|
|
|
|
ensName, err = m.settings.ENSName()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get display name of a current user
|
|
|
|
displayName, err = m.settings.DisplayName()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
response, err = m.sendContactUpdate(context.Background(), pubKey, displayName, ensName, "", m.account.GetCustomizationColor(), m.dispatchMessage)
|
2023-01-20 14:28:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-02-10 12:20:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(contactRequestID) != 0 {
|
2024-05-15 00:01:47 +00:00
|
|
|
updatedResponse, err := m.updateAcceptedContactRequest(response, contactRequestID, "", false)
|
2023-02-10 12:20:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = response.Merge(updatedResponse)
|
2022-01-18 16:31:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-21 18:08:11 +00:00
|
|
|
// Sends a standalone ChatIdentity message
|
2021-10-22 14:20:42 +00:00
|
|
|
err = m.handleStandaloneChatIdentity(chat)
|
2020-12-22 10:49:25 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-08-03 14:16:11 +00:00
|
|
|
// Profile chats are deprecated.
|
|
|
|
// Code below can be removed after some reasonable time.
|
|
|
|
|
2023-02-21 18:08:11 +00:00
|
|
|
// Add chat
|
2023-08-03 14:16:11 +00:00
|
|
|
if !deprecation.ChatProfileDeprecated {
|
|
|
|
response.AddChat(profileChat)
|
2021-10-22 14:20:42 +00:00
|
|
|
|
2023-11-15 15:58:15 +00:00
|
|
|
_, err = m.transport.InitFilters([]transport.FiltersToInitialize{{ChatID: profileChat.ID}}, []*ecdsa.PublicKey{publicKey})
|
2023-08-03 14:16:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2021-09-29 08:21:05 +00:00
|
|
|
// Publish contact code
|
|
|
|
err = m.publishContactCode()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-07-12 15:12:58 +00:00
|
|
|
// Add mutual state update message for outgoing contact request
|
|
|
|
if len(contactRequestID) == 0 {
|
2023-02-21 18:08:11 +00:00
|
|
|
clock, timestamp := chat.NextClockAndTimestamp(m.transport)
|
2023-07-12 15:12:58 +00:00
|
|
|
updateMessage, err := m.prepareMutualStateUpdateMessage(contact.ID, MutualStateUpdateTypeSent, clock, timestamp, true)
|
2023-02-21 18:08:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-01-08 18:18:57 +00:00
|
|
|
err = m.prepareMessage(updateMessage, m.httpServer)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-07-12 15:12:58 +00:00
|
|
|
err = m.persistence.SaveMessages([]*common.Message{updateMessage})
|
2023-04-25 11:27:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-07-12 15:12:58 +00:00
|
|
|
response.AddMessage(updateMessage)
|
2023-08-11 17:08:54 +00:00
|
|
|
err = chat.UpdateFromMessage(updateMessage, m.getTimesource())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-07-12 15:12:58 +00:00
|
|
|
response.AddChat(chat)
|
|
|
|
}
|
2023-04-25 11:27:15 +00:00
|
|
|
|
2023-07-12 15:12:58 +00:00
|
|
|
// Add outgoing contact request notification
|
|
|
|
if createOutgoingContactRequestNotification {
|
|
|
|
clock, timestamp := chat.NextClockAndTimestamp(m.transport)
|
|
|
|
contactRequest, err := m.generateContactRequest(clock, timestamp, contact, contactRequestText, true)
|
2023-02-21 18:08:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-07-12 15:12:58 +00:00
|
|
|
// Send contact request as a plain chat message
|
|
|
|
messageResponse, err := m.sendChatMessage(ctx, contactRequest)
|
2023-06-08 12:00:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-07-12 15:12:58 +00:00
|
|
|
err = response.Merge(messageResponse)
|
2023-06-08 12:00:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-21 18:08:11 +00:00
|
|
|
notification := m.generateOutgoingContactRequestNotification(contact, contactRequest)
|
2023-10-22 09:41:20 +00:00
|
|
|
err = m.addActivityCenterNotification(response, notification, nil)
|
2023-02-21 18:08:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add contact
|
2022-01-18 16:31:34 +00:00
|
|
|
response.AddContact(contact)
|
2020-12-22 10:49:25 +00:00
|
|
|
return response, nil
|
|
|
|
}
|
2023-01-20 14:28:30 +00:00
|
|
|
|
2023-04-25 11:27:15 +00:00
|
|
|
func (m *Messenger) generateContactRequest(clock uint64, timestamp uint64, contact *Contact, text string, outgoing bool) (*common.Message, error) {
|
2023-02-21 18:08:11 +00:00
|
|
|
if contact == nil {
|
|
|
|
return nil, errors.New("contact cannot be nil")
|
|
|
|
}
|
|
|
|
|
2023-08-18 11:39:59 +00:00
|
|
|
contactRequest := common.NewMessage()
|
2023-04-25 11:27:15 +00:00
|
|
|
contactRequest.ChatId = contact.ID
|
2023-02-21 18:08:11 +00:00
|
|
|
contactRequest.WhisperTimestamp = timestamp
|
|
|
|
contactRequest.Seen = true
|
|
|
|
contactRequest.Text = text
|
2023-04-25 11:27:15 +00:00
|
|
|
if outgoing {
|
|
|
|
contactRequest.From = m.myHexIdentity()
|
2024-04-03 14:49:57 +00:00
|
|
|
contactRequest.CustomizationColor = m.account.GetCustomizationColorID()
|
2023-04-25 11:27:15 +00:00
|
|
|
} else {
|
|
|
|
contactRequest.From = contact.ID
|
2024-04-03 14:49:57 +00:00
|
|
|
contactRequest.CustomizationColor = multiaccountscommon.ColorToIDFallbackToBlue(contact.CustomizationColor)
|
2023-04-25 11:27:15 +00:00
|
|
|
}
|
2023-02-21 18:08:11 +00:00
|
|
|
contactRequest.LocalChatID = contact.ID
|
|
|
|
contactRequest.ContentType = protobuf.ChatMessage_CONTACT_REQUEST
|
|
|
|
contactRequest.Clock = clock
|
|
|
|
if contact.mutual() {
|
|
|
|
contactRequest.ContactRequestState = common.ContactRequestStateAccepted
|
|
|
|
} else {
|
|
|
|
contactRequest.ContactRequestState = common.ContactRequestStatePending
|
|
|
|
}
|
|
|
|
err := contactRequest.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey))
|
|
|
|
return contactRequest, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Messenger) generateOutgoingContactRequestNotification(contact *Contact, contactRequest *common.Message) *ActivityCenterNotification {
|
|
|
|
return &ActivityCenterNotification{
|
|
|
|
ID: types.FromHex(contactRequest.ID),
|
|
|
|
Type: ActivityCenterNotificationTypeContactRequest,
|
2023-02-22 16:57:33 +00:00
|
|
|
Name: contact.PrimaryName(),
|
2023-02-21 18:08:11 +00:00
|
|
|
Author: m.myHexIdentity(),
|
|
|
|
Message: contactRequest,
|
|
|
|
Timestamp: m.getTimesource().GetCurrentTime(),
|
|
|
|
ChatID: contact.ID,
|
2023-04-25 11:27:15 +00:00
|
|
|
Read: contactRequest.ContactRequestState == common.ContactRequestStateAccepted ||
|
|
|
|
contactRequest.ContactRequestState == common.ContactRequestStateDismissed ||
|
|
|
|
contactRequest.ContactRequestState == common.ContactRequestStatePending,
|
2023-02-21 18:08:11 +00:00
|
|
|
Accepted: contactRequest.ContactRequestState == common.ContactRequestStateAccepted,
|
|
|
|
Dismissed: contactRequest.ContactRequestState == common.ContactRequestStateDismissed,
|
2023-10-22 09:41:20 +00:00
|
|
|
UpdatedAt: m.GetCurrentTimeInMillis(),
|
2023-02-21 18:08:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-18 16:31:34 +00:00
|
|
|
func (m *Messenger) AddContact(ctx context.Context, request *requests.AddContact) (*MessengerResponse, error) {
|
|
|
|
err := request.Validate()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-10-14 08:50:36 +00:00
|
|
|
id, err := request.HexID()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-21 18:08:11 +00:00
|
|
|
return m.addContact(
|
2023-04-25 11:27:15 +00:00
|
|
|
ctx,
|
2022-10-14 08:50:36 +00:00
|
|
|
id,
|
2023-02-21 18:08:11 +00:00
|
|
|
request.ENSName,
|
|
|
|
request.Nickname,
|
|
|
|
request.DisplayName,
|
2024-04-03 14:49:57 +00:00
|
|
|
multiaccountscommon.CustomizationColor(request.CustomizationColor),
|
2023-02-21 18:08:11 +00:00
|
|
|
"",
|
2023-05-22 12:22:33 +00:00
|
|
|
defaultContactRequestText(),
|
2023-02-21 18:08:11 +00:00
|
|
|
false,
|
|
|
|
true,
|
|
|
|
true,
|
|
|
|
)
|
2022-01-18 16:31:34 +00:00
|
|
|
}
|
2020-12-22 10:49:25 +00:00
|
|
|
|
2021-10-07 15:02:01 +00:00
|
|
|
func (m *Messenger) resetLastPublishedTimeForChatIdentity() error {
|
|
|
|
// Reset last published time for ChatIdentity so new contact can receive data
|
|
|
|
contactCodeTopic := transport.ContactCodeTopic(&m.identity.PublicKey)
|
|
|
|
m.logger.Debug("contact state changed ResetWhenChatIdentityLastPublished")
|
|
|
|
return m.persistence.ResetWhenChatIdentityLastPublished(contactCodeTopic)
|
|
|
|
}
|
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
func (m *Messenger) removeContact(ctx context.Context, response *MessengerResponse, pubKey string, sync bool) error {
|
2021-03-29 15:41:30 +00:00
|
|
|
contact, ok := m.allContacts.Load(pubKey)
|
2020-12-22 10:49:25 +00:00
|
|
|
if !ok {
|
2021-09-03 08:26:05 +00:00
|
|
|
return ErrContactNotFound
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2023-06-08 12:00:19 +00:00
|
|
|
// System message for mutual state update
|
|
|
|
chat, clock, err := m.getOneToOneAndNextClock(contact)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
timestamp := m.getTimesource().GetCurrentTime()
|
|
|
|
updateMessage, err := m.prepareMutualStateUpdateMessage(contact.ID, MutualStateUpdateTypeRemoved, clock, timestamp, true)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-01-08 18:18:57 +00:00
|
|
|
err = m.prepareMessage(updateMessage, m.httpServer)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-06-08 12:00:19 +00:00
|
|
|
err = m.persistence.SaveMessages([]*common.Message{updateMessage})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
response.AddMessage(updateMessage)
|
2023-08-11 17:08:54 +00:00
|
|
|
err = chat.UpdateFromMessage(updateMessage, m.getTimesource())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-06-08 12:00:19 +00:00
|
|
|
response.AddChat(chat)
|
|
|
|
|
|
|
|
// Next we retract a contact request
|
2023-01-20 14:28:30 +00:00
|
|
|
contact.RetractContactRequest(clock)
|
|
|
|
contact.LastUpdatedLocally = m.getTimesource().GetCurrentTime()
|
|
|
|
|
|
|
|
err = m.persistence.SaveContact(contact, nil)
|
2021-09-03 08:26:05 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
if sync {
|
|
|
|
err = m.syncContact(context.Background(), contact, m.dispatchMessage)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:41:30 +00:00
|
|
|
// TODO(samyoul) remove storing of an updated reference pointer?
|
|
|
|
m.allContacts.Store(contact.ID, contact)
|
2020-12-22 10:49:25 +00:00
|
|
|
|
|
|
|
// And we re-register for push notications
|
|
|
|
err = m.reregisterForPushNotifications()
|
|
|
|
if err != nil {
|
2021-09-03 08:26:05 +00:00
|
|
|
return err
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2024-02-09 09:36:54 +00:00
|
|
|
// Dispatch profile message to remove a contact from the encrypted profile part
|
|
|
|
err = m.DispatchProfileShowcase()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-08-03 14:16:11 +00:00
|
|
|
// Profile chats are deprecated.
|
|
|
|
// Code below can be removed after some reasonable time.
|
2020-12-22 10:49:25 +00:00
|
|
|
|
2023-08-03 14:16:11 +00:00
|
|
|
//Create the corresponding profile chat
|
|
|
|
if !deprecation.ChatProfileDeprecated {
|
|
|
|
profileChatID := buildProfileChatID(contact.ID)
|
|
|
|
_, ok = m.allChats.Load(profileChatID)
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
chatResponse, err := m.deactivateChat(profileChatID, 0, false, true)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = response.Merge(chatResponse)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
response.Contacts = []*Contact{contact}
|
2021-09-03 08:26:05 +00:00
|
|
|
return nil
|
|
|
|
}
|
2022-01-18 16:31:34 +00:00
|
|
|
|
2021-09-03 08:26:05 +00:00
|
|
|
func (m *Messenger) RemoveContact(ctx context.Context, pubKey string) (*MessengerResponse, error) {
|
|
|
|
response := new(MessengerResponse)
|
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
err := m.removeContact(ctx, response, pubKey, true)
|
2021-09-03 08:26:05 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-12-22 10:49:25 +00:00
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
2023-06-06 18:06:11 +00:00
|
|
|
func (m *Messenger) updateContactImagesURL(contact *Contact) error {
|
|
|
|
if m.httpServer != nil {
|
|
|
|
for k, v := range contact.Images {
|
|
|
|
publicKey, err := contact.PublicKey()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
v.LocalURL = m.httpServer.MakeContactImageURL(common.PubkeyToHex(publicKey), k)
|
|
|
|
contact.Images[k] = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-22 10:49:25 +00:00
|
|
|
func (m *Messenger) Contacts() []*Contact {
|
|
|
|
var contacts []*Contact
|
2021-03-29 15:41:30 +00:00
|
|
|
m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
|
2021-03-24 08:04:03 +00:00
|
|
|
contacts = append(contacts, contact)
|
2021-03-29 15:41:30 +00:00
|
|
|
return true
|
|
|
|
})
|
2020-12-22 10:49:25 +00:00
|
|
|
return contacts
|
|
|
|
}
|
|
|
|
|
2021-10-11 15:39:52 +00:00
|
|
|
func (m *Messenger) AddedContacts() []*Contact {
|
|
|
|
var contacts []*Contact
|
|
|
|
m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
|
2023-01-20 14:28:30 +00:00
|
|
|
if contact.added() {
|
2021-10-11 15:39:52 +00:00
|
|
|
contacts = append(contacts, contact)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
return contacts
|
|
|
|
}
|
|
|
|
|
2022-01-18 16:31:34 +00:00
|
|
|
func (m *Messenger) MutualContacts() []*Contact {
|
|
|
|
var contacts []*Contact
|
|
|
|
m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
|
2023-01-20 14:28:30 +00:00
|
|
|
if contact.mutual() {
|
2022-01-18 16:31:34 +00:00
|
|
|
contacts = append(contacts, contact)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
return contacts
|
|
|
|
}
|
|
|
|
|
2021-11-05 15:11:10 +00:00
|
|
|
func (m *Messenger) BlockedContacts() []*Contact {
|
|
|
|
var contacts []*Contact
|
|
|
|
m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
|
|
|
|
if contact.Blocked {
|
|
|
|
contacts = append(contacts, contact)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
return contacts
|
|
|
|
}
|
|
|
|
|
2023-10-24 10:15:32 +00:00
|
|
|
// GetContactByID returns a Contact for given pubKey, if it's known.
|
|
|
|
// This function automatically checks if pubKey is self identity key and returns a Contact
|
|
|
|
// filled with self information.
|
|
|
|
// pubKey is assumed to include `0x` prefix
|
2020-12-22 10:49:25 +00:00
|
|
|
func (m *Messenger) GetContactByID(pubKey string) *Contact {
|
2023-10-24 10:15:32 +00:00
|
|
|
if pubKey == m.IdentityPublicKeyString() {
|
|
|
|
return m.selfContact
|
|
|
|
}
|
2021-03-29 15:41:30 +00:00
|
|
|
contact, _ := m.allContacts.Load(pubKey)
|
|
|
|
return contact
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-13 20:07:35 +00:00
|
|
|
func (m *Messenger) GetSelfContact() *Contact {
|
|
|
|
return m.selfContact
|
|
|
|
}
|
|
|
|
|
2021-10-25 10:25:37 +00:00
|
|
|
func (m *Messenger) SetContactLocalNickname(request *requests.SetContactLocalNickname) (*MessengerResponse, error) {
|
|
|
|
|
|
|
|
if err := request.Validate(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
pubKey := request.ID.String()
|
|
|
|
nickname := request.Nickname
|
2021-10-22 14:20:42 +00:00
|
|
|
|
2023-03-14 15:34:35 +00:00
|
|
|
contact, err := m.BuildContact(&requests.BuildContact{PublicKey: pubKey})
|
2023-01-20 14:28:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2021-10-22 14:20:42 +00:00
|
|
|
}
|
|
|
|
|
2021-10-26 10:48:02 +00:00
|
|
|
if err := m.addENSNameToContact(contact); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-10-22 14:20:42 +00:00
|
|
|
clock := m.getTimesource().GetCurrentTime()
|
|
|
|
contact.LocalNickname = nickname
|
|
|
|
contact.LastUpdatedLocally = clock
|
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
err = m.persistence.SaveContact(contact, nil)
|
2021-10-25 10:25:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-11-05 15:11:10 +00:00
|
|
|
m.allContacts.Store(contact.ID, contact)
|
|
|
|
|
2021-10-22 14:20:42 +00:00
|
|
|
response := &MessengerResponse{}
|
|
|
|
response.Contacts = []*Contact{contact}
|
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
err = m.syncContact(context.Background(), contact, m.dispatchMessage)
|
2021-10-22 14:20:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
2023-10-22 09:41:20 +00:00
|
|
|
func (m *Messenger) blockContact(ctx context.Context, response *MessengerResponse, contactID string, isDesktopFunc bool, fromSyncing bool) error {
|
2023-03-14 15:34:35 +00:00
|
|
|
contact, err := m.BuildContact(&requests.BuildContact{PublicKey: contactID})
|
2023-01-20 14:28:30 +00:00
|
|
|
if err != nil {
|
2023-08-04 10:41:24 +00:00
|
|
|
return err
|
2021-11-05 15:11:10 +00:00
|
|
|
}
|
2023-01-20 14:28:30 +00:00
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
response.AddContact(contact)
|
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
_, clock, err := m.getOneToOneAndNextClock(contact)
|
|
|
|
if err != nil {
|
2023-08-04 10:41:24 +00:00
|
|
|
return err
|
2022-04-08 20:14:37 +00:00
|
|
|
}
|
2022-07-07 08:49:52 +00:00
|
|
|
|
2024-02-26 17:49:04 +00:00
|
|
|
contactWasAdded := contact.added()
|
2023-01-20 14:28:30 +00:00
|
|
|
contact.Block(clock)
|
|
|
|
|
2021-10-22 14:20:42 +00:00
|
|
|
contact.LastUpdatedLocally = m.getTimesource().GetCurrentTime()
|
|
|
|
|
2022-04-08 20:14:37 +00:00
|
|
|
chats, err := m.persistence.BlockContact(contact, isDesktopFunc)
|
2020-12-22 10:49:25 +00:00
|
|
|
if err != nil {
|
2023-08-04 10:41:24 +00:00
|
|
|
return err
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
response.AddChats(chats)
|
2023-04-20 10:52:08 +00:00
|
|
|
|
2021-03-29 15:41:30 +00:00
|
|
|
m.allContacts.Store(contact.ID, contact)
|
2020-12-22 10:49:25 +00:00
|
|
|
for _, chat := range chats {
|
2021-03-29 15:41:30 +00:00
|
|
|
m.allChats.Store(chat.ID, chat)
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
2022-04-08 20:14:37 +00:00
|
|
|
|
|
|
|
if !isDesktopFunc {
|
|
|
|
m.allChats.Delete(contact.ID)
|
|
|
|
m.allChats.Delete(buildProfileChatID(contact.ID))
|
|
|
|
}
|
2020-12-22 10:49:25 +00:00
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
if !fromSyncing {
|
2024-02-26 17:49:04 +00:00
|
|
|
if contactWasAdded {
|
|
|
|
err = m.sendRetractContactRequest(contact)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-08-04 10:41:24 +00:00
|
|
|
}
|
2021-09-03 08:26:05 +00:00
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
err = m.syncContact(context.Background(), contact, m.dispatchMessage)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-12-22 10:49:25 +00:00
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
// We remove anything that's related to this contact request
|
2023-10-22 09:41:20 +00:00
|
|
|
updatedAt := m.GetCurrentTimeInMillis()
|
|
|
|
notifications, err := m.persistence.DeleteChatContactRequestActivityCenterNotifications(contact.ID, updatedAt)
|
2023-08-04 10:41:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-10-22 09:41:20 +00:00
|
|
|
err = m.syncActivityCenterDeleted(ctx, notifications, updatedAt)
|
2023-08-04 10:41:24 +00:00
|
|
|
if err != nil {
|
2023-10-22 09:41:20 +00:00
|
|
|
m.logger.Error("BlockContact, error syncing activity center notifications as deleted", zap.Error(err))
|
2023-08-04 10:41:24 +00:00
|
|
|
return err
|
|
|
|
}
|
2023-06-08 12:00:19 +00:00
|
|
|
}
|
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
// re-register for push notifications
|
|
|
|
err = m.reregisterForPushNotifications()
|
2023-06-10 02:00:17 +00:00
|
|
|
if err != nil {
|
2023-08-04 10:41:24 +00:00
|
|
|
return err
|
2023-06-10 02:00:17 +00:00
|
|
|
}
|
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
return nil
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2023-10-22 09:41:20 +00:00
|
|
|
func (m *Messenger) BlockContact(ctx context.Context, contactID string, fromSyncing bool) (*MessengerResponse, error) {
|
2021-12-06 12:44:40 +00:00
|
|
|
response := &MessengerResponse{}
|
|
|
|
|
2023-10-22 09:41:20 +00:00
|
|
|
err := m.blockContact(ctx, response, contactID, false, fromSyncing)
|
2022-04-08 20:14:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-10-22 09:41:20 +00:00
|
|
|
response, err = m.DeclineAllPendingGroupInvitesFromUser(ctx, response, contactID)
|
2022-04-08 20:14:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-08-04 10:41:24 +00:00
|
|
|
// AC notifications are synced separately
|
|
|
|
// NOTE: Should we still do the local part (persistence.dismiss...) and only skip the syncing?
|
|
|
|
// This would make the solution more reliable even in case AC notification sync is not recevied.
|
|
|
|
// This should be considered separately, I'm not sure if that's safe.
|
|
|
|
// https://github.com/status-im/status-go/issues/3720
|
|
|
|
if !fromSyncing {
|
2023-10-22 09:41:20 +00:00
|
|
|
updatedAt := m.GetCurrentTimeInMillis()
|
|
|
|
_, err = m.DismissAllActivityCenterNotificationsFromUser(ctx, contactID, updatedAt)
|
2023-08-04 10:41:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-04-08 20:14:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// The same function as the one above.
|
2023-08-04 10:41:24 +00:00
|
|
|
// Should be removed with https://github.com/status-im/status-desktop/issues/8805
|
2023-10-22 09:41:20 +00:00
|
|
|
func (m *Messenger) BlockContactDesktop(ctx context.Context, contactID string) (*MessengerResponse, error) {
|
2022-04-08 20:14:37 +00:00
|
|
|
response := &MessengerResponse{}
|
|
|
|
|
2023-10-22 09:41:20 +00:00
|
|
|
err := m.blockContact(ctx, response, contactID, true, false)
|
2021-12-06 12:44:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-10-22 09:41:20 +00:00
|
|
|
response, err = m.DeclineAllPendingGroupInvitesFromUser(ctx, response, contactID)
|
2021-12-06 12:44:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-10-22 09:41:20 +00:00
|
|
|
notifications, err := m.DismissAllActivityCenterNotificationsFromUser(ctx, contactID, m.GetCurrentTimeInMillis())
|
2023-06-10 02:00:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-10-22 09:41:20 +00:00
|
|
|
response.AddActivityCenterNotifications(notifications)
|
2021-12-06 12:44:40 +00:00
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
2023-06-01 17:26:12 +00:00
|
|
|
func (m *Messenger) UnblockContact(contactID string) (*MessengerResponse, error) {
|
|
|
|
response := &MessengerResponse{}
|
2021-10-25 07:18:28 +00:00
|
|
|
contact, ok := m.allContacts.Load(contactID)
|
2021-10-27 10:59:43 +00:00
|
|
|
if !ok || !contact.Blocked {
|
2023-06-01 17:26:12 +00:00
|
|
|
return response, nil
|
2021-10-25 07:18:28 +00:00
|
|
|
}
|
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
_, clock, err := m.getOneToOneAndNextClock(contact)
|
|
|
|
if err != nil {
|
2023-06-01 17:26:12 +00:00
|
|
|
return nil, err
|
2023-01-20 14:28:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
contact.Unblock(clock)
|
|
|
|
|
2021-10-25 07:18:28 +00:00
|
|
|
contact.LastUpdatedLocally = m.getTimesource().GetCurrentTime()
|
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
err = m.persistence.SaveContact(contact, nil)
|
2021-12-03 12:38:09 +00:00
|
|
|
if err != nil {
|
2023-06-01 17:26:12 +00:00
|
|
|
return nil, err
|
2021-12-03 12:38:09 +00:00
|
|
|
}
|
|
|
|
|
2021-10-25 07:18:28 +00:00
|
|
|
m.allContacts.Store(contact.ID, contact)
|
|
|
|
|
2023-06-01 17:26:12 +00:00
|
|
|
response.AddContact(contact)
|
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
err = m.syncContact(context.Background(), contact, m.dispatchMessage)
|
2021-10-25 07:18:28 +00:00
|
|
|
if err != nil {
|
2023-06-01 17:26:12 +00:00
|
|
|
return nil, err
|
2021-10-25 07:18:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// re-register for push notifications
|
|
|
|
err = m.reregisterForPushNotifications()
|
|
|
|
if err != nil {
|
2023-06-01 17:26:12 +00:00
|
|
|
return nil, err
|
2021-10-25 07:18:28 +00:00
|
|
|
}
|
|
|
|
|
2023-06-01 17:26:12 +00:00
|
|
|
return response, nil
|
2021-10-25 07:18:28 +00:00
|
|
|
}
|
|
|
|
|
2020-12-22 10:49:25 +00:00
|
|
|
// Send contact updates to all contacts added by us
|
2024-04-03 14:49:57 +00:00
|
|
|
func (m *Messenger) SendContactUpdates(ctx context.Context, ensName, profileImage string, customizationColor multiaccountscommon.CustomizationColor) (err error) {
|
2020-12-22 10:49:25 +00:00
|
|
|
myID := contactIDFromPublicKey(&m.identity.PublicKey)
|
|
|
|
|
2022-02-17 15:13:10 +00:00
|
|
|
displayName, err := m.settings.DisplayName()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-04-03 14:49:57 +00:00
|
|
|
if len(customizationColor) == 0 && m.account != nil {
|
|
|
|
customizationColor = m.account.GetCustomizationColor()
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err = m.sendContactUpdate(ctx, myID, displayName, ensName, profileImage, customizationColor, m.dispatchMessage); err != nil {
|
2020-12-22 10:49:25 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: This should not be sending paired messages, as we do it above
|
2021-03-29 15:41:30 +00:00
|
|
|
m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
|
2023-01-20 14:28:30 +00:00
|
|
|
if contact.added() {
|
2024-04-03 14:49:57 +00:00
|
|
|
if _, err = m.sendContactUpdate(ctx, contact.ID, displayName, ensName, profileImage, customizationColor, m.dispatchMessage); err != nil {
|
2021-03-29 15:41:30 +00:00
|
|
|
return false
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-29 15:41:30 +00:00
|
|
|
return true
|
|
|
|
})
|
|
|
|
return err
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: this endpoint does not add the contact, the reason being is that currently
|
|
|
|
// that's left as a responsibility to the client, which will call both `SendContactUpdate`
|
|
|
|
// and `SaveContact` with the correct system tag.
|
|
|
|
// Ideally we have a single endpoint that does both, but probably best to bring `ENS` name
|
|
|
|
// on the messenger first.
|
|
|
|
|
|
|
|
// SendContactUpdate sends a contact update to a user and adds the user to contacts
|
2024-04-03 14:49:57 +00:00
|
|
|
func (m *Messenger) SendContactUpdate(ctx context.Context, chatID, ensName, profileImage string, customizationColor multiaccountscommon.CustomizationColor) (*MessengerResponse, error) {
|
2022-02-17 15:13:10 +00:00
|
|
|
displayName, err := m.settings.DisplayName()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-04-03 14:49:57 +00:00
|
|
|
return m.sendContactUpdate(ctx, chatID, displayName, ensName, profileImage, customizationColor, m.dispatchMessage)
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2024-04-03 14:49:57 +00:00
|
|
|
func (m *Messenger) sendContactUpdate(ctx context.Context,
|
|
|
|
chatID, displayName, ensName, profileImage string,
|
|
|
|
customizationColor multiaccountscommon.CustomizationColor,
|
|
|
|
rawMessageHandler RawMessageHandler) (*MessengerResponse, error) {
|
2020-12-22 10:49:25 +00:00
|
|
|
var response MessengerResponse
|
|
|
|
|
2021-03-29 15:41:30 +00:00
|
|
|
contact, ok := m.allContacts.Load(chatID)
|
2023-01-20 14:28:30 +00:00
|
|
|
if !ok || !contact.added() {
|
2021-10-22 14:20:42 +00:00
|
|
|
return nil, nil
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
2023-01-20 14:28:30 +00:00
|
|
|
chat, clock, err := m.getOneToOneAndNextClock(contact)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
contactUpdate := &protobuf.ContactUpdate{
|
2023-02-02 18:12:20 +00:00
|
|
|
Clock: clock,
|
|
|
|
DisplayName: displayName,
|
|
|
|
EnsName: ensName,
|
|
|
|
ProfileImage: profileImage,
|
|
|
|
ContactRequestClock: contact.ContactRequestLocalClock,
|
|
|
|
ContactRequestPropagatedState: contact.ContactRequestPropagatedState(),
|
2023-03-28 03:45:54 +00:00
|
|
|
PublicKey: contact.ID,
|
2024-04-03 14:49:57 +00:00
|
|
|
CustomizationColor: multiaccountscommon.ColorToIDFallbackToBlue(customizationColor),
|
2022-02-17 15:13:10 +00:00
|
|
|
}
|
2024-04-03 14:49:57 +00:00
|
|
|
|
2020-12-22 10:49:25 +00:00
|
|
|
encodedMessage, err := proto.Marshal(contactUpdate)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
rawMessage := common.RawMessage{
|
2024-03-22 10:55:09 +00:00
|
|
|
LocalChatID: chatID,
|
|
|
|
Payload: encodedMessage,
|
|
|
|
MessageType: protobuf.ApplicationMetadataMessage_CONTACT_UPDATE,
|
|
|
|
ResendType: common.ResendTypeDataSync,
|
2023-01-06 12:21:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_, err = rawMessageHandler(ctx, rawMessage)
|
2020-12-22 10:49:25 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
response.Contacts = []*Contact{contact}
|
2021-01-11 10:32:51 +00:00
|
|
|
response.AddChat(chat)
|
2020-12-22 10:49:25 +00:00
|
|
|
|
|
|
|
chat.LastClockValue = clock
|
|
|
|
err = m.saveChat(chat)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-10-22 14:20:42 +00:00
|
|
|
return &response, nil
|
2020-12-22 10:49:25 +00:00
|
|
|
}
|
2021-10-26 10:48:02 +00:00
|
|
|
|
|
|
|
func (m *Messenger) addENSNameToContact(contact *Contact) error {
|
|
|
|
|
|
|
|
// Check if there's already a verified record
|
|
|
|
ensRecord, err := m.ensVerifier.GetVerifiedRecord(contact.ID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if ensRecord == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-02-17 15:13:10 +00:00
|
|
|
contact.EnsName = ensRecord.Name
|
2021-10-26 10:48:02 +00:00
|
|
|
contact.ENSVerified = true
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2022-01-18 16:31:34 +00:00
|
|
|
|
2022-07-22 11:59:32 +00:00
|
|
|
func (m *Messenger) RetractContactRequest(request *requests.RetractContactRequest) (*MessengerResponse, error) {
|
|
|
|
err := request.Validate()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-02-21 18:08:11 +00:00
|
|
|
contact, ok := m.allContacts.Load(request.ID.String())
|
2022-07-22 11:59:32 +00:00
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("contact not found")
|
|
|
|
}
|
2022-01-18 16:31:34 +00:00
|
|
|
response := &MessengerResponse{}
|
2023-01-20 14:28:30 +00:00
|
|
|
err = m.removeContact(context.Background(), response, contact.ID, true)
|
2022-01-18 16:31:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-07-22 11:59:32 +00:00
|
|
|
|
|
|
|
err = m.sendRetractContactRequest(contact)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return response, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send message to remote account to remove our contact from their end.
|
|
|
|
func (m *Messenger) sendRetractContactRequest(contact *Contact) error {
|
2023-01-20 14:28:30 +00:00
|
|
|
_, clock, err := m.getOneToOneAndNextClock(contact)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2022-01-18 16:31:34 +00:00
|
|
|
}
|
|
|
|
retractContactRequest := &protobuf.RetractContactRequest{
|
|
|
|
Clock: clock,
|
|
|
|
}
|
2022-07-22 11:59:32 +00:00
|
|
|
|
2022-01-18 16:31:34 +00:00
|
|
|
encodedMessage, err := proto.Marshal(retractContactRequest)
|
|
|
|
if err != nil {
|
2022-07-22 11:59:32 +00:00
|
|
|
return err
|
2022-01-18 16:31:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_, err = m.dispatchMessage(context.Background(), common.RawMessage{
|
2024-03-22 10:55:09 +00:00
|
|
|
LocalChatID: contact.ID,
|
|
|
|
Payload: encodedMessage,
|
|
|
|
MessageType: protobuf.ApplicationMetadataMessage_RETRACT_CONTACT_REQUEST,
|
|
|
|
ResendType: common.ResendTypeDataSync,
|
2022-01-18 16:31:34 +00:00
|
|
|
})
|
2023-06-08 12:00:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-01-18 16:31:34 +00:00
|
|
|
|
2022-07-22 11:59:32 +00:00
|
|
|
return err
|
2022-07-07 08:49:52 +00:00
|
|
|
}
|
|
|
|
|
2024-02-28 20:00:35 +00:00
|
|
|
func (m *Messenger) GetLatestContactRequestForContact(contactID string) (*MessengerResponse, error) {
|
|
|
|
if len(contactID) == 0 {
|
|
|
|
return nil, ErrGetLatestContactRequestForContactInvalidID
|
|
|
|
}
|
|
|
|
|
|
|
|
contactRequestID, err := m.persistence.LatestPendingContactRequestIDForContact(contactID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
contactRequest, err := m.persistence.MessageByID(contactRequestID)
|
|
|
|
if err != nil {
|
|
|
|
m.logger.Error("contact request not found", zap.String("contactRequestID", contactRequestID), zap.Error(err))
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
response := &MessengerResponse{}
|
|
|
|
response.AddMessage(contactRequest)
|
|
|
|
|
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
2022-06-17 16:20:43 +00:00
|
|
|
func (m *Messenger) AcceptLatestContactRequestForContact(ctx context.Context, request *requests.AcceptLatestContactRequestForContact) (*MessengerResponse, error) {
|
|
|
|
if err := request.Validate(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
contactRequestID, err := m.persistence.LatestPendingContactRequestIDForContact(request.ID.String())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return m.AcceptContactRequest(ctx, &requests.AcceptContactRequest{ID: types.Hex2Bytes(contactRequestID)})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Messenger) DismissLatestContactRequestForContact(ctx context.Context, request *requests.DismissLatestContactRequestForContact) (*MessengerResponse, error) {
|
|
|
|
if err := request.Validate(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
contactRequestID, err := m.persistence.LatestPendingContactRequestIDForContact(request.ID.String())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-21 18:08:11 +00:00
|
|
|
return m.DeclineContactRequest(ctx, &requests.DeclineContactRequest{ID: types.Hex2Bytes(contactRequestID)})
|
2022-06-17 16:20:43 +00:00
|
|
|
}
|
|
|
|
|
2022-01-18 16:31:34 +00:00
|
|
|
func (m *Messenger) PendingContactRequests(cursor string, limit int) ([]*common.Message, string, error) {
|
|
|
|
return m.persistence.PendingContactRequests(cursor, limit)
|
|
|
|
}
|
2022-06-13 10:57:51 +00:00
|
|
|
|
|
|
|
func defaultContactRequestID(contactID string) string {
|
|
|
|
return "0x" + types.Bytes2Hex(append(types.Hex2Bytes(contactID), 0x20))
|
|
|
|
}
|
2023-01-20 18:51:36 +00:00
|
|
|
|
2023-05-22 12:22:33 +00:00
|
|
|
func defaultContactRequestText() string {
|
|
|
|
return "Please add me to your contacts"
|
|
|
|
}
|
|
|
|
|
2023-03-14 15:34:35 +00:00
|
|
|
func (m *Messenger) BuildContact(request *requests.BuildContact) (*Contact, error) {
|
|
|
|
contact, ok := m.allContacts.Load(request.PublicKey)
|
2023-01-20 18:51:36 +00:00
|
|
|
if !ok {
|
|
|
|
var err error
|
2023-03-14 15:34:35 +00:00
|
|
|
contact, err = buildContactFromPkString(request.PublicKey)
|
2023-01-20 18:51:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-03-14 15:34:35 +00:00
|
|
|
|
|
|
|
if request.ENSName != "" {
|
|
|
|
contact.ENSVerified = true
|
|
|
|
contact.EnsName = request.ENSName
|
|
|
|
}
|
2024-04-03 14:49:57 +00:00
|
|
|
|
|
|
|
if len(contact.CustomizationColor) == 0 {
|
|
|
|
contact.CustomizationColor = multiaccountscommon.CustomizationColorBlue
|
|
|
|
}
|
2023-01-20 18:51:36 +00:00
|
|
|
}
|
2023-03-14 09:00:05 +00:00
|
|
|
|
|
|
|
// Schedule sync filter to fetch information about the contact
|
|
|
|
publicKey, err := contact.PublicKey()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-04-05 20:25:44 +00:00
|
|
|
|
|
|
|
_, err = m.scheduleSyncFiltersForContact(publicKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return contact, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Messenger) scheduleSyncFiltersForContact(publicKey *ecdsa.PublicKey) (*transport.Filter, error) {
|
2023-03-14 09:00:05 +00:00
|
|
|
filter, err := m.transport.JoinPrivate(publicKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_, err = m.scheduleSyncFilters([]*transport.Filter{filter})
|
2023-04-05 20:25:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return filter, err
|
|
|
|
}
|
|
|
|
return filter, nil
|
|
|
|
}
|
|
|
|
|
2023-12-20 12:49:12 +00:00
|
|
|
func (m *Messenger) FetchContact(contactID string, waitForResponse bool) (*Contact, error) {
|
2023-12-27 13:53:19 +00:00
|
|
|
options := []StoreNodeRequestOption{
|
|
|
|
WithWaitForResponseOption(waitForResponse),
|
|
|
|
}
|
|
|
|
contact, _, err := m.storeNodeRequestsManager.FetchContact(contactID, options)
|
2023-12-20 12:49:12 +00:00
|
|
|
return contact, err
|
2023-04-05 20:25:44 +00:00
|
|
|
}
|
2023-11-13 20:07:35 +00:00
|
|
|
|
|
|
|
func (m *Messenger) SubscribeToSelfContactChanges() chan *SelfContactChangeEvent {
|
|
|
|
s := make(chan *SelfContactChangeEvent, 10)
|
|
|
|
m.selfContactSubscriptions = append(m.selfContactSubscriptions, s)
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Messenger) publishSelfContactSubscriptions(event *SelfContactChangeEvent) {
|
|
|
|
for _, s := range m.selfContactSubscriptions {
|
|
|
|
select {
|
|
|
|
case s <- event:
|
|
|
|
default:
|
test_: Code Migration from status-cli-tests
author shashankshampi <shashank.sanket1995@gmail.com> 1729780155 +0530
committer shashankshampi <shashank.sanket1995@gmail.com> 1730274350 +0530
test: Code Migration from status-cli-tests
fix_: functional tests (#5979)
* fix_: generate on test-functional
* chore(test)_: fix functional test assertion
---------
Co-authored-by: Siddarth Kumar <siddarthkay@gmail.com>
feat(accounts)_: cherry-pick Persist acceptance of Terms of Use & Privacy policy (#5766) (#5977)
* feat(accounts)_: Persist acceptance of Terms of Use & Privacy policy (#5766)
The original GH issue https://github.com/status-im/status-mobile/issues/21113
came from a request from the Legal team. We must show to Status v1 users the new
terms (Terms of Use & Privacy Policy) right after they upgrade to Status v2
from the stores.
The solution we use is to create a flag in the accounts table, named
hasAcceptedTerms. The flag will be set to true on the first account ever
created in v2 and we provide a native call in mobile/status.go#AcceptTerms,
which allows the client to persist the user's choice in case they are upgrading
(from v1 -> v2, or from a v2 older than this PR).
This solution is not the best because we should store the setting in a separate
table, not in the accounts table.
Related Mobile PR https://github.com/status-im/status-mobile/pull/21124
* fix(test)_: Compare addresses using uppercased strings
---------
Co-authored-by: Icaro Motta <icaro.ldm@gmail.com>
test_: restore account (#5960)
feat_: `LogOnPanic` linter (#5969)
* feat_: LogOnPanic linter
* fix_: add missing defer LogOnPanic
* chore_: make vendor
* fix_: tests, address pr comments
* fix_: address pr comments
fix(ci)_: remove workspace and tmp dir
This ensures we do not encounter weird errors like:
```
+ ln -s /home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907 /home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907@tmp/go/src/github.com/status-im/status-go
ln: failed to create symbolic link '/home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907@tmp/go/src/github.com/status-im/status-go': File exists
script returned exit code 1
```
Signed-off-by: Jakub Sokołowski <jakub@status.im>
chore_: enable windows and macos CI build (#5840)
- Added support for Windows and macOS in CI pipelines
- Added missing dependencies for Windows and x86-64-darwin
- Resolved macOS SDK version compatibility for darwin-x86_64
The `mkShell` override was necessary to ensure compatibility with the newer
macOS SDK (version 11.0) for x86_64. The default SDK (10.12) was causing build failures
because of the missing libs and frameworks. OverrideSDK creates a mapping from
the default SDK in all package categories to the requested SDK (11.0).
fix(contacts)_: fix trust status not being saved to cache when changed (#5965)
Fixes https://github.com/status-im/status-desktop/issues/16392
cleanup
added logger and cleanup
review comments changes
fix_: functional tests (#5979)
* fix_: generate on test-functional
* chore(test)_: fix functional test assertion
---------
Co-authored-by: Siddarth Kumar <siddarthkay@gmail.com>
feat(accounts)_: cherry-pick Persist acceptance of Terms of Use & Privacy policy (#5766) (#5977)
* feat(accounts)_: Persist acceptance of Terms of Use & Privacy policy (#5766)
The original GH issue https://github.com/status-im/status-mobile/issues/21113
came from a request from the Legal team. We must show to Status v1 users the new
terms (Terms of Use & Privacy Policy) right after they upgrade to Status v2
from the stores.
The solution we use is to create a flag in the accounts table, named
hasAcceptedTerms. The flag will be set to true on the first account ever
created in v2 and we provide a native call in mobile/status.go#AcceptTerms,
which allows the client to persist the user's choice in case they are upgrading
(from v1 -> v2, or from a v2 older than this PR).
This solution is not the best because we should store the setting in a separate
table, not in the accounts table.
Related Mobile PR https://github.com/status-im/status-mobile/pull/21124
* fix(test)_: Compare addresses using uppercased strings
---------
Co-authored-by: Icaro Motta <icaro.ldm@gmail.com>
test_: restore account (#5960)
feat_: `LogOnPanic` linter (#5969)
* feat_: LogOnPanic linter
* fix_: add missing defer LogOnPanic
* chore_: make vendor
* fix_: tests, address pr comments
* fix_: address pr comments
chore_: enable windows and macos CI build (#5840)
- Added support for Windows and macOS in CI pipelines
- Added missing dependencies for Windows and x86-64-darwin
- Resolved macOS SDK version compatibility for darwin-x86_64
The `mkShell` override was necessary to ensure compatibility with the newer
macOS SDK (version 11.0) for x86_64. The default SDK (10.12) was causing build failures
because of the missing libs and frameworks. OverrideSDK creates a mapping from
the default SDK in all package categories to the requested SDK (11.0).
fix(contacts)_: fix trust status not being saved to cache when changed (#5965)
Fixes https://github.com/status-im/status-desktop/issues/16392
test_: remove port bind
chore(wallet)_: move route execution code to separate module
chore_: replace geth logger with zap logger (#5962)
closes: #6002
feat(telemetry)_: add metrics for message reliability (#5899)
* feat(telemetry)_: track message reliability
Add metrics for dial errors, missed messages,
missed relevant messages, and confirmed delivery.
* fix_: handle error from json marshal
chore_: use zap logger as request logger
iterates: status-im/status-desktop#16536
test_: unique project per run
test_: use docker compose v2, more concrete project name
fix(codecov)_: ignore folders without tests
Otherwise Codecov reports incorrect numbers when making changes.
https://docs.codecov.com/docs/ignoring-paths
Signed-off-by: Jakub Sokołowski <jakub@status.im>
test_: verify schema of signals during init; fix schema verification warnings (#5947)
fix_: update defaultGorushURL (#6011)
fix(tests)_: use non-standard port to avoid conflicts
We have observed `nimbus-eth2` build failures reporting this port:
```json
{
"lvl": "NTC",
"ts": "2024-10-28 13:51:32.308+00:00",
"msg": "REST HTTP server could not be started",
"topics": "beacnde",
"address": "127.0.0.1:5432",
"reason": "(98) Address already in use"
}
```
https://ci.status.im/job/nimbus-eth2/job/platforms/job/linux/job/x86_64/job/main/job/PR-6683/3/
Signed-off-by: Jakub Sokołowski <jakub@status.im>
fix_: create request logger ad-hoc in tests
Fixes `TestCall` failing when run concurrently.
chore_: configure codecov (#6005)
* chore_: configure codecov
* fix_: after_n_builds
2024-10-24 14:29:15 +00:00
|
|
|
logutils.ZapLogger().Warn("self contact subscription channel full, dropping message")
|
2023-11-13 20:07:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|