github.com/status-im/status-go@v1.1.0/protocol/messenger_identity.go (about)

     1  package protocol
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"runtime"
     7  	"strings"
     8  	"unicode/utf8"
     9  
    10  	utils "github.com/status-im/status-go/common"
    11  	"github.com/status-im/status-go/multiaccounts/settings"
    12  	"github.com/status-im/status-go/protocol/encryption/multidevice"
    13  	"github.com/status-im/status-go/server"
    14  )
    15  
    16  const (
    17  	maxBioLength = 240
    18  )
    19  
    20  var ErrInvalidBioLength = errors.New("invalid bio length")
    21  var ErrDisplayNameDupeOfCommunityMember = errors.New("display name duplicates on of community members")
    22  
    23  func (m *Messenger) SetDisplayName(displayName string) error {
    24  	currDisplayName, err := m.settings.DisplayName()
    25  	if err != nil {
    26  		return err
    27  	}
    28  
    29  	if utils.IsENSName(displayName) || currDisplayName == displayName {
    30  		return nil // Do nothing
    31  	}
    32  
    33  	if err = utils.ValidateDisplayName(&displayName); err != nil {
    34  		return err
    35  	}
    36  
    37  	isDupe, err := m.IsDisplayNameDupeOfCommunityMember(displayName)
    38  	if err != nil {
    39  		return err
    40  	}
    41  
    42  	if isDupe {
    43  		return ErrDisplayNameDupeOfCommunityMember
    44  	}
    45  
    46  	m.account.Name = displayName
    47  	err = m.multiAccounts.UpdateDisplayName(m.account.KeyUID, displayName)
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	err = m.settings.SaveSettingField(settings.DisplayName, displayName)
    53  	if err != nil {
    54  		return err
    55  	}
    56  
    57  	err = m.UpdateKeypairName(m.account.KeyUID, displayName)
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	err = m.resetLastPublishedTimeForChatIdentity()
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	return m.publishContactCode()
    68  }
    69  
    70  func (m *Messenger) SaveSyncDisplayName(displayName string, clock uint64) error {
    71  	err := m.settings.SaveSyncSetting(settings.DisplayName, displayName, clock)
    72  	if err != nil {
    73  		return err
    74  	}
    75  
    76  	preferredName, err := m.settings.GetPreferredUsername()
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	preferredNameClock, err := m.settings.GetSettingLastSynced(settings.PreferredName)
    82  	if err != nil {
    83  		return err
    84  	}
    85  	// When either the display name or preferred name changes, m.account.Name should be updated.
    86  	// However, a race condition can occur during BackupData, where m.account.Name could be incorrectly updated.
    87  	// The final value of m.account.Name depends on which backup message(BackedUpProfile/BackedUpSettings) arrives later.
    88  	// So we should check the clock of the preferred name and only update m.account.Name if it's older than the display name.
    89  	// Yet even if the preferred name clock is older, but the preferred name was empty, we should still update m.account.Name.
    90  
    91  	if preferredNameClock < clock || preferredName == "" {
    92  		m.account.Name = displayName
    93  		return m.multiAccounts.SaveAccount(*m.account)
    94  	}
    95  	return nil
    96  }
    97  
    98  func ValidateBio(bio *string) error {
    99  	if utf8.RuneCountInString(*bio) > maxBioLength {
   100  		return ErrInvalidBioLength
   101  	}
   102  	return nil
   103  }
   104  
   105  func (m *Messenger) SetBio(bio string) error {
   106  	currentBio, err := m.settings.Bio()
   107  	if err != nil {
   108  		return err
   109  	}
   110  
   111  	if currentBio == bio {
   112  		return nil // Do nothing
   113  	}
   114  
   115  	if err = ValidateBio(&bio); err != nil {
   116  		return err
   117  	}
   118  
   119  	if err = m.settings.SaveSettingField(settings.Bio, bio); err != nil {
   120  		return err
   121  	}
   122  
   123  	if err = m.resetLastPublishedTimeForChatIdentity(); err != nil {
   124  		return err
   125  	}
   126  
   127  	return m.publishContactCode()
   128  }
   129  
   130  func (m *Messenger) setInstallationHostname() error {
   131  	imd, err := m.getOurInstallationMetadata()
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	// If the name and device are already set, don't do anything
   137  	if len(imd.Name) != 0 && len(imd.DeviceType) != 0 {
   138  		return nil
   139  	}
   140  
   141  	if len(imd.Name) == 0 {
   142  		deviceName, err := m.settings.DeviceName()
   143  		if err != nil {
   144  			return err
   145  		}
   146  		if deviceName != "" {
   147  			imd.Name = deviceName
   148  		} else {
   149  			hn, err := server.GetDeviceName()
   150  			if err != nil {
   151  				return err
   152  			}
   153  			// NOTE: imd.Name is always empty in this else branch, which leads to the
   154  			// result of Sprintf having a trailing whitespace.
   155  			imd.Name = fmt.Sprintf("%s %s", hn, imd.Name)
   156  		}
   157  	}
   158  
   159  	if len(imd.DeviceType) == 0 {
   160  		imd.DeviceType = runtime.GOOS
   161  	}
   162  
   163  	return m.setInstallationMetadata(m.installationID, imd)
   164  
   165  }
   166  
   167  func (m *Messenger) getOurInstallationMetadata() (*multidevice.InstallationMetadata, error) {
   168  	ourInstallation, ok := m.allInstallations.Load(m.installationID)
   169  	if !ok {
   170  		return nil, fmt.Errorf("messenger's installationID is not set or not loadable")
   171  	}
   172  
   173  	if ourInstallation.InstallationMetadata == nil {
   174  		return new(multidevice.InstallationMetadata), nil
   175  	}
   176  
   177  	return ourInstallation.InstallationMetadata, nil
   178  }
   179  
   180  func (m *Messenger) SetInstallationDeviceType(deviceType string) error {
   181  	if strings.TrimSpace(deviceType) == "" {
   182  		return errors.New("device type is empty")
   183  	}
   184  
   185  	imd, err := m.getOurInstallationMetadata()
   186  	if err != nil {
   187  		return err
   188  	}
   189  
   190  	// If the name is already set, don't do anything
   191  	if len(imd.DeviceType) != 0 {
   192  		return nil
   193  	}
   194  
   195  	imd.DeviceType = deviceType
   196  	return m.setInstallationMetadata(m.installationID, imd)
   197  }