738 lines
21 KiB
Go
738 lines
21 KiB
Go
package protocol
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
|
"github.com/status-im/status-go/protocol/common"
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
|
"github.com/status-im/status-go/protocol/verification"
|
|
)
|
|
|
|
const minContactVerificationMessageLen = 1
|
|
const maxContactVerificationMessageLen = 280
|
|
|
|
func (m *Messenger) SendContactVerificationRequest(ctx context.Context, contactID string, challenge string) error {
|
|
if len(challenge) < minContactVerificationMessageLen || len(challenge) > maxContactVerificationMessageLen {
|
|
return errors.New("invalid verification request challenge length")
|
|
}
|
|
|
|
contact, ok := m.allContacts.Load(contactID)
|
|
if !ok || !contact.Added || !contact.HasAddedUs {
|
|
return errors.New("must be a mutual contact")
|
|
}
|
|
|
|
verifRequest, err := m.verificationDatabase.GetVerificationRequestFrom(contactID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if verifRequest != nil && verifRequest.RequestStatus == verification.RequestStatusACCEPTED {
|
|
return errors.New("verification request already accepted")
|
|
}
|
|
|
|
if verifRequest != nil && verifRequest.RequestStatus == verification.RequestStatusPENDING {
|
|
return errors.New("verification request already sent")
|
|
}
|
|
|
|
if verifRequest == nil {
|
|
verifRequest = &verification.Request{
|
|
From: common.PubkeyToHex(&m.identity.PublicKey),
|
|
To: contact.ID,
|
|
Challenge: challenge,
|
|
RequestStatus: verification.RequestStatusPENDING,
|
|
RepliedAt: 0,
|
|
}
|
|
}
|
|
|
|
chat, ok := m.allChats.Load(contactID)
|
|
if !ok {
|
|
publicKey, err := contact.PublicKey()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
chat = OneToOneFromPublicKey(publicKey, m.getTimesource())
|
|
// We don't want to show the chat to the user
|
|
chat.Active = false
|
|
}
|
|
|
|
m.allChats.Store(chat.ID, chat)
|
|
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
|
|
|
|
request := &protobuf.RequestContactVerification{
|
|
Clock: clock,
|
|
Challenge: challenge,
|
|
}
|
|
|
|
encodedMessage, err := proto.Marshal(request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = m.dispatchMessage(ctx, common.RawMessage{
|
|
LocalChatID: chat.ID,
|
|
Payload: encodedMessage,
|
|
MessageType: protobuf.ApplicationMetadataMessage_REQUEST_CONTACT_VERIFICATION,
|
|
ResendAutomatically: true,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
contact.VerificationStatus = VerificationStatusVERIFYING
|
|
contact.LastUpdatedLocally = m.getTimesource().GetCurrentTime()
|
|
|
|
err = m.persistence.SaveContact(contact, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// We sync the contact with the other devices
|
|
err = m.syncContact(context.Background(), contact)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
m.allContacts.Store(contact.ID, contact)
|
|
|
|
verifRequest.RequestedAt = clock
|
|
|
|
err = m.verificationDatabase.SaveVerificationRequest(verifRequest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return m.SyncVerificationRequest(context.Background(), verifRequest)
|
|
}
|
|
|
|
func (m *Messenger) GetVerificationRequestSentTo(ctx context.Context, contactID string) (*verification.Request, error) {
|
|
_, ok := m.allContacts.Load(contactID)
|
|
if !ok {
|
|
return nil, errors.New("contact not found")
|
|
}
|
|
|
|
return m.verificationDatabase.GetVerificationRequestSentTo(contactID)
|
|
}
|
|
|
|
func (m *Messenger) GetVerificationRequestFrom(ctx context.Context, contactID string) (*verification.Request, error) {
|
|
_, ok := m.allContacts.Load(contactID)
|
|
if !ok {
|
|
return nil, errors.New("contact not found")
|
|
}
|
|
|
|
return m.verificationDatabase.GetVerificationRequestFrom(contactID)
|
|
}
|
|
|
|
func (m *Messenger) GetReceivedVerificationRequests(ctx context.Context) ([]*verification.Request, error) {
|
|
myPubKey := hexutil.Encode(crypto.FromECDSAPub(&m.identity.PublicKey))
|
|
return m.verificationDatabase.GetReceivedVerificationRequests(myPubKey)
|
|
}
|
|
|
|
func (m *Messenger) CancelVerificationRequest(ctx context.Context, contactID string) error {
|
|
contact, ok := m.allContacts.Load(contactID)
|
|
if !ok || !contact.Added || !contact.HasAddedUs {
|
|
return errors.New("must be a mutual contact")
|
|
}
|
|
|
|
verifRequest, err := m.verificationDatabase.GetVerificationRequestSentTo(contactID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if verifRequest == nil {
|
|
return errors.New("no contact verification found")
|
|
}
|
|
|
|
if verifRequest.RequestStatus != verification.RequestStatusPENDING {
|
|
return errors.New("can't cancel a request already verified")
|
|
}
|
|
|
|
verifRequest.RequestStatus = verification.RequestStatusCANCELED
|
|
err = m.verificationDatabase.SaveVerificationRequest(verifRequest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
contact.VerificationStatus = VerificationStatusUNVERIFIED
|
|
contact.LastUpdatedLocally = m.getTimesource().GetCurrentTime()
|
|
|
|
err = m.persistence.SaveContact(contact, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// We sync the contact with the other devices
|
|
err = m.syncContact(context.Background(), contact)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = m.SyncVerificationRequest(context.Background(), verifRequest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
m.allContacts.Store(contact.ID, contact)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Messenger) AcceptContactVerificationRequest(ctx context.Context, contactID string, response string) error {
|
|
contact, ok := m.allContacts.Load(contactID)
|
|
if !ok || !contact.Added || !contact.HasAddedUs {
|
|
return errors.New("must be a mutual contact")
|
|
}
|
|
|
|
verifRequest, err := m.verificationDatabase.GetVerificationRequestFrom(contactID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if verifRequest == nil {
|
|
return errors.New("no contact verification found")
|
|
}
|
|
|
|
chat, ok := m.allChats.Load(contactID)
|
|
if !ok {
|
|
publicKey, err := contact.PublicKey()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
chat = OneToOneFromPublicKey(publicKey, m.getTimesource())
|
|
// We don't want to show the chat to the user
|
|
chat.Active = false
|
|
}
|
|
|
|
m.allChats.Store(chat.ID, chat)
|
|
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
|
|
|
|
verifRequest.RequestStatus = verification.RequestStatusACCEPTED
|
|
verifRequest.RepliedAt = clock
|
|
err = m.verificationDatabase.SaveVerificationRequest(verifRequest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = m.SyncVerificationRequest(context.Background(), verifRequest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
request := &protobuf.AcceptContactVerification{
|
|
Clock: clock,
|
|
Response: response,
|
|
}
|
|
|
|
encodedMessage, err := proto.Marshal(request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = m.dispatchMessage(ctx, common.RawMessage{
|
|
LocalChatID: chat.ID,
|
|
Payload: encodedMessage,
|
|
MessageType: protobuf.ApplicationMetadataMessage_ACCEPT_CONTACT_VERIFICATION,
|
|
ResendAutomatically: true,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return m.verificationDatabase.AcceptContactVerificationRequest(contactID, response)
|
|
}
|
|
|
|
func (m *Messenger) VerifiedTrusted(ctx context.Context, contactID string) error {
|
|
contact, ok := m.allContacts.Load(contactID)
|
|
if !ok || !contact.Added || !contact.HasAddedUs {
|
|
return errors.New("must be a mutual contact")
|
|
}
|
|
|
|
err := m.verificationDatabase.SetTrustStatus(contactID, verification.TrustStatusTRUSTED, m.getTimesource().GetCurrentTime())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = m.SyncTrustedUser(context.Background(), contactID, verification.TrustStatusTRUSTED)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
contact.VerificationStatus = VerificationStatusVERIFIED
|
|
contact.LastUpdatedLocally = m.getTimesource().GetCurrentTime()
|
|
err = m.persistence.SaveContact(contact, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
chat, ok := m.allChats.Load(contactID)
|
|
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
|
|
if !ok {
|
|
publicKey, err := contact.PublicKey()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
chat = OneToOneFromPublicKey(publicKey, m.getTimesource())
|
|
// We don't want to show the chat to the user
|
|
chat.Active = false
|
|
}
|
|
|
|
request := &protobuf.ContactVerificationTrusted{
|
|
Clock: clock,
|
|
}
|
|
|
|
encodedMessage, err := proto.Marshal(request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = m.dispatchMessage(ctx, common.RawMessage{
|
|
LocalChatID: chat.ID,
|
|
Payload: encodedMessage,
|
|
MessageType: protobuf.ApplicationMetadataMessage_CONTACT_VERIFICATION_TRUSTED,
|
|
ResendAutomatically: true,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
verifRequest, err := m.verificationDatabase.GetVerificationRequestSentTo(contactID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if verifRequest == nil {
|
|
return errors.New("no contact verification found")
|
|
}
|
|
|
|
verifRequest.RequestStatus = verification.RequestStatusTRUSTED
|
|
verifRequest.RepliedAt = clock
|
|
err = m.verificationDatabase.SaveVerificationRequest(verifRequest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = m.SyncVerificationRequest(context.Background(), verifRequest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// We sync the contact with the other devices
|
|
err = m.syncContact(context.Background(), contact)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Messenger) VerifiedUntrustworthy(ctx context.Context, contactID string) error {
|
|
contact, ok := m.allContacts.Load(contactID)
|
|
if !ok || !contact.Added || !contact.HasAddedUs {
|
|
return errors.New("must be a mutual contact")
|
|
}
|
|
|
|
err := m.verificationDatabase.SetTrustStatus(contactID, verification.TrustStatusUNTRUSTWORTHY, m.getTimesource().GetCurrentTime())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = m.SyncTrustedUser(context.Background(), contactID, verification.TrustStatusUNTRUSTWORTHY)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
contact.VerificationStatus = VerificationStatusVERIFIED
|
|
contact.LastUpdatedLocally = m.getTimesource().GetCurrentTime()
|
|
err = m.persistence.SaveContact(contact, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// We sync the contact with the other devices
|
|
err = m.syncContact(context.Background(), contact)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Messenger) DeclineContactVerificationRequest(ctx context.Context, contactID string) error {
|
|
contact, ok := m.allContacts.Load(contactID)
|
|
if !ok || !contact.Added || !contact.HasAddedUs {
|
|
return errors.New("must be a mutual contact")
|
|
}
|
|
|
|
verifRequest, err := m.verificationDatabase.GetVerificationRequestFrom(contactID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if verifRequest == nil {
|
|
return errors.New("no contact verification found")
|
|
}
|
|
|
|
chat, ok := m.allChats.Load(contactID)
|
|
if !ok {
|
|
publicKey, err := contact.PublicKey()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
chat = OneToOneFromPublicKey(publicKey, m.getTimesource())
|
|
// We don't want to show the chat to the user
|
|
chat.Active = false
|
|
}
|
|
|
|
m.allChats.Store(chat.ID, chat)
|
|
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
|
|
|
|
verifRequest.RequestStatus = verification.RequestStatusDECLINED
|
|
verifRequest.RepliedAt = clock
|
|
err = m.verificationDatabase.SaveVerificationRequest(verifRequest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = m.SyncVerificationRequest(context.Background(), verifRequest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
request := &protobuf.DeclineContactVerification{
|
|
Clock: clock,
|
|
}
|
|
|
|
encodedMessage, err := proto.Marshal(request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = m.dispatchMessage(ctx, common.RawMessage{
|
|
LocalChatID: chat.ID,
|
|
Payload: encodedMessage,
|
|
MessageType: protobuf.ApplicationMetadataMessage_DECLINE_CONTACT_VERIFICATION,
|
|
ResendAutomatically: true,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return m.verificationDatabase.DeclineContactVerificationRequest(contactID)
|
|
}
|
|
|
|
func (m *Messenger) MarkAsTrusted(ctx context.Context, contactID string) error {
|
|
err := m.verificationDatabase.SetTrustStatus(contactID, verification.TrustStatusTRUSTED, m.getTimesource().GetCurrentTime())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return m.SyncTrustedUser(ctx, contactID, verification.TrustStatusTRUSTED)
|
|
}
|
|
|
|
func (m *Messenger) MarkAsUntrustworthy(ctx context.Context, contactID string) error {
|
|
err := m.verificationDatabase.SetTrustStatus(contactID, verification.TrustStatusUNTRUSTWORTHY, m.getTimesource().GetCurrentTime())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return m.SyncTrustedUser(ctx, contactID, verification.TrustStatusUNTRUSTWORTHY)
|
|
}
|
|
|
|
func (m *Messenger) RemoveTrustStatus(ctx context.Context, contactID string) error {
|
|
err := m.verificationDatabase.SetTrustStatus(contactID, verification.TrustStatusUNKNOWN, m.getTimesource().GetCurrentTime())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return m.SyncTrustedUser(ctx, contactID, verification.TrustStatusUNKNOWN)
|
|
}
|
|
|
|
func (m *Messenger) GetTrustStatus(contactID string) (verification.TrustStatus, error) {
|
|
return m.verificationDatabase.GetTrustStatus(contactID)
|
|
}
|
|
|
|
func ValidateContactVerificationRequest(request protobuf.RequestContactVerification) error {
|
|
challengeLen := len(strings.TrimSpace(request.Challenge))
|
|
if challengeLen < minContactVerificationMessageLen || challengeLen > maxContactVerificationMessageLen {
|
|
return errors.New("invalid verification request challenge length")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Messenger) HandleRequestContactVerification(state *ReceivedMessageState, request protobuf.RequestContactVerification) error {
|
|
if err := ValidateContactVerificationRequest(request); err != nil {
|
|
m.logger.Debug("Invalid verification request", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if common.IsPubKeyEqual(state.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
|
|
return nil // Is ours, do nothing
|
|
}
|
|
|
|
myPubKey := hexutil.Encode(crypto.FromECDSAPub(&m.identity.PublicKey))
|
|
contactID := hexutil.Encode(crypto.FromECDSAPub(state.CurrentMessageState.PublicKey))
|
|
|
|
contact := state.CurrentMessageState.Contact
|
|
if !contact.Added || !contact.HasAddedUs {
|
|
m.logger.Debug("Received a verification request for a non added mutual contact", zap.String("contactID", contactID))
|
|
return errors.New("must be a mutual contact")
|
|
}
|
|
|
|
persistedVR, err := m.verificationDatabase.GetVerificationRequestFrom(contactID)
|
|
if err != nil {
|
|
m.logger.Debug("Error obtaining verification request", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if persistedVR != nil && persistedVR.RequestedAt > request.Clock {
|
|
return nil // older message, ignore it
|
|
}
|
|
|
|
if persistedVR == nil {
|
|
// This is a new verification request, and we have not received its acceptance/decline before
|
|
persistedVR = &verification.Request{}
|
|
persistedVR.From = contactID
|
|
persistedVR.To = myPubKey
|
|
persistedVR.RequestStatus = verification.RequestStatusPENDING
|
|
}
|
|
|
|
persistedVR.Challenge = request.Challenge
|
|
persistedVR.RequestedAt = request.Clock
|
|
|
|
err = m.verificationDatabase.SaveVerificationRequest(persistedVR)
|
|
if err != nil {
|
|
m.logger.Debug("Error storing verification request", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
err = m.SyncVerificationRequest(context.Background(), persistedVR)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
state.AllVerificationRequests = append(state.AllVerificationRequests, persistedVR)
|
|
|
|
// TODO: create or update activity center notification
|
|
|
|
return nil
|
|
}
|
|
|
|
func ValidateAcceptContactVerification(request protobuf.AcceptContactVerification) error {
|
|
responseLen := len(strings.TrimSpace(request.Response))
|
|
if responseLen < minContactVerificationMessageLen || responseLen > maxContactVerificationMessageLen {
|
|
return errors.New("invalid verification request response length")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Messenger) HandleAcceptContactVerification(state *ReceivedMessageState, request protobuf.AcceptContactVerification) error {
|
|
if err := ValidateAcceptContactVerification(request); err != nil {
|
|
m.logger.Debug("Invalid AcceptContactVerification", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if common.IsPubKeyEqual(state.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
|
|
return nil // Is ours, do nothing
|
|
}
|
|
|
|
myPubKey := hexutil.Encode(crypto.FromECDSAPub(&m.identity.PublicKey))
|
|
contactID := hexutil.Encode(crypto.FromECDSAPub(state.CurrentMessageState.PublicKey))
|
|
|
|
contact := state.CurrentMessageState.Contact
|
|
if !contact.Added || !contact.HasAddedUs {
|
|
m.logger.Debug("Received a verification response for a non mutual contact", zap.String("contactID", contactID))
|
|
return errors.New("must be a mutual contact")
|
|
}
|
|
|
|
persistedVR, err := m.verificationDatabase.GetVerificationRequestSentTo(contactID)
|
|
if err != nil {
|
|
m.logger.Debug("Error obtaining verification request", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if persistedVR != nil && persistedVR.RepliedAt > request.Clock {
|
|
return nil // older message, ignore it
|
|
}
|
|
|
|
if persistedVR.RequestStatus == verification.RequestStatusCANCELED {
|
|
return nil // Do nothing, We have already cancelled the verification request
|
|
}
|
|
|
|
if persistedVR == nil {
|
|
// This is a response for which we have not received its request before
|
|
persistedVR = &verification.Request{}
|
|
persistedVR.From = contactID
|
|
persistedVR.To = myPubKey
|
|
}
|
|
|
|
persistedVR.RequestStatus = verification.RequestStatusACCEPTED
|
|
persistedVR.Response = request.Response
|
|
persistedVR.RepliedAt = request.Clock
|
|
|
|
err = m.verificationDatabase.SaveVerificationRequest(persistedVR)
|
|
if err != nil {
|
|
m.logger.Debug("Error storing verification request", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
err = m.SyncVerificationRequest(context.Background(), persistedVR)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
state.AllVerificationRequests = append(state.AllVerificationRequests, persistedVR)
|
|
|
|
// TODO: create or update activity center notification
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Messenger) HandleDeclineContactVerification(state *ReceivedMessageState, request protobuf.DeclineContactVerification) error {
|
|
if common.IsPubKeyEqual(state.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
|
|
return nil // Is ours, do nothing
|
|
}
|
|
|
|
myPubKey := hexutil.Encode(crypto.FromECDSAPub(&m.identity.PublicKey))
|
|
contactID := hexutil.Encode(crypto.FromECDSAPub(state.CurrentMessageState.PublicKey))
|
|
|
|
contact := state.CurrentMessageState.Contact
|
|
if !contact.Added || !contact.HasAddedUs {
|
|
m.logger.Debug("Received a verification decline for a non mutual contact", zap.String("contactID", contactID))
|
|
return errors.New("must be a mutual contact")
|
|
}
|
|
|
|
persistedVR, err := m.verificationDatabase.GetVerificationRequestSentTo(contactID)
|
|
if err != nil {
|
|
m.logger.Debug("Error obtaining verification request", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if persistedVR != nil && persistedVR.RepliedAt > request.Clock {
|
|
return nil // older message, ignore it
|
|
}
|
|
|
|
if persistedVR.RequestStatus == verification.RequestStatusCANCELED {
|
|
return nil // Do nothing, We have already cancelled the verification request
|
|
}
|
|
|
|
if persistedVR == nil {
|
|
// This is a response for which we have not received its request before
|
|
persistedVR = &verification.Request{}
|
|
persistedVR.From = contactID
|
|
persistedVR.To = myPubKey
|
|
}
|
|
|
|
persistedVR.RequestStatus = verification.RequestStatusDECLINED
|
|
persistedVR.RepliedAt = request.Clock
|
|
|
|
err = m.verificationDatabase.SaveVerificationRequest(persistedVR)
|
|
if err != nil {
|
|
m.logger.Debug("Error storing verification request", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
err = m.SyncVerificationRequest(context.Background(), persistedVR)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
state.AllVerificationRequests = append(state.AllVerificationRequests, persistedVR)
|
|
|
|
// TODO: create or update activity center notification
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Messenger) HandleContactVerificationTrusted(state *ReceivedMessageState, request protobuf.ContactVerificationTrusted) error {
|
|
if common.IsPubKeyEqual(state.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
|
|
return nil // Is ours, do nothing
|
|
}
|
|
|
|
myPubKey := hexutil.Encode(crypto.FromECDSAPub(&m.identity.PublicKey))
|
|
contactID := hexutil.Encode(crypto.FromECDSAPub(state.CurrentMessageState.PublicKey))
|
|
|
|
contact := state.CurrentMessageState.Contact
|
|
if !contact.Added || !contact.HasAddedUs {
|
|
m.logger.Debug("Received a verification trusted for a non mutual contact", zap.String("contactID", contactID))
|
|
return errors.New("must be a mutual contact")
|
|
}
|
|
|
|
err := m.verificationDatabase.SetTrustStatus(contactID, verification.TrustStatusTRUSTED, m.getTimesource().GetCurrentTime())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = m.SyncTrustedUser(context.Background(), contactID, verification.TrustStatusTRUSTED)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
persistedVR, err := m.verificationDatabase.GetVerificationRequestFrom(contactID)
|
|
if err != nil {
|
|
m.logger.Debug("Error obtaining verification request", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if persistedVR != nil && persistedVR.RepliedAt > request.Clock {
|
|
return nil // older message, ignore it
|
|
}
|
|
|
|
if persistedVR.RequestStatus == verification.RequestStatusCANCELED {
|
|
return nil // Do nothing, We have already cancelled the verification request
|
|
}
|
|
|
|
if persistedVR == nil {
|
|
// This is a response for which we have not received its request before
|
|
persistedVR = &verification.Request{}
|
|
persistedVR.From = contactID
|
|
persistedVR.To = myPubKey
|
|
}
|
|
|
|
persistedVR.RequestStatus = verification.RequestStatusTRUSTED
|
|
|
|
err = m.verificationDatabase.SaveVerificationRequest(persistedVR)
|
|
if err != nil {
|
|
m.logger.Debug("Error storing verification request", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
err = m.SyncVerificationRequest(context.Background(), persistedVR)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
state.AllVerificationRequests = append(state.AllVerificationRequests, persistedVR)
|
|
|
|
contact.VerificationStatus = VerificationStatusVERIFIED
|
|
contact.LastUpdatedLocally = m.getTimesource().GetCurrentTime()
|
|
err = m.persistence.SaveContact(contact, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
state.ModifiedContacts.Store(contact.ID, true)
|
|
state.AllContacts.Store(contact.ID, contact)
|
|
|
|
// We sync the contact with the other devices
|
|
err = m.syncContact(context.Background(), contact)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// TODO: create or update activity center notification
|
|
|
|
return nil
|
|
}
|