github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/mobile/mysterium/identity.go (about)

     1  /*
     2   * Copyright (C) 2021 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package mysterium
    19  
    20  import (
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"math/big"
    25  
    26  	"github.com/mysteriumnetwork/node/identity"
    27  	"github.com/mysteriumnetwork/node/identity/registry"
    28  	"github.com/mysteriumnetwork/payments/crypto"
    29  )
    30  
    31  // GetIdentityRequest represents identity request.
    32  type GetIdentityRequest struct {
    33  	Address    string
    34  	Passphrase string
    35  }
    36  
    37  // GetIdentityResponse represents identity response.
    38  type GetIdentityResponse struct {
    39  	IdentityAddress    string
    40  	ChannelAddress     string
    41  	RegistrationStatus string
    42  }
    43  
    44  // GetIdentity finds first identity and unlocks it.
    45  // If there is no identity default one will be created.
    46  func (mb *MobileNode) GetIdentity(req *GetIdentityRequest) (*GetIdentityResponse, error) {
    47  	if req == nil {
    48  		req = &GetIdentityRequest{}
    49  	}
    50  
    51  	id, err := mb.identitySelector.UseOrCreate(req.Address, req.Passphrase, mb.chainID)
    52  	if err != nil {
    53  		return nil, fmt.Errorf("could not unlock identity: %w", err)
    54  	}
    55  
    56  	channelAddress, err := mb.identityChannelCalculator.GetActiveChannelAddress(mb.chainID, id.ToCommonAddress())
    57  	if err != nil {
    58  		return nil, fmt.Errorf("could not generate channel address: %w", err)
    59  	}
    60  
    61  	status, err := mb.identityRegistry.GetRegistrationStatus(mb.chainID, id)
    62  	if err != nil {
    63  		return nil, fmt.Errorf("could not get identity registration status: %w", err)
    64  	}
    65  
    66  	return &GetIdentityResponse{
    67  		IdentityAddress:    id.Address,
    68  		ChannelAddress:     channelAddress.Hex(),
    69  		RegistrationStatus: status.String(),
    70  	}, nil
    71  }
    72  
    73  // GetIdentityRegistrationFeesResponse represents identity registration fees result.
    74  type GetIdentityRegistrationFeesResponse struct {
    75  	Fee float64
    76  }
    77  
    78  // GetIdentityRegistrationFees returns identity registration fees.
    79  func (mb *MobileNode) GetIdentityRegistrationFees() (*GetIdentityRegistrationFeesResponse, error) {
    80  	fees, err := mb.transactor.FetchRegistrationFees(mb.chainID)
    81  	if err != nil {
    82  		return nil, fmt.Errorf("could not get registration fees: %w", err)
    83  	}
    84  
    85  	fee := crypto.BigMystToFloat(fees.Fee)
    86  
    87  	return &GetIdentityRegistrationFeesResponse{Fee: fee}, nil
    88  }
    89  
    90  // RegisterIdentityRequest represents identity registration request.
    91  type RegisterIdentityRequest struct {
    92  	IdentityAddress string
    93  	Token           string
    94  }
    95  
    96  // RegisterIdentity starts identity registration in background.
    97  func (mb *MobileNode) RegisterIdentity(req *RegisterIdentityRequest) error {
    98  	fees, err := mb.transactor.FetchRegistrationFees(mb.chainID)
    99  	if err != nil {
   100  		return fmt.Errorf("could not get registration fees: %w", err)
   101  	}
   102  
   103  	var token *string
   104  	if req.Token != "" {
   105  		token = &req.Token
   106  	}
   107  
   108  	err = mb.transactor.RegisterIdentity(req.IdentityAddress, big.NewInt(0), fees.Fee, "", mb.chainID, token)
   109  	if err != nil {
   110  		return fmt.Errorf("could not register identity: %w", err)
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  // IdentityRegistrationChangeCallback represents identity registration status callback.
   117  type IdentityRegistrationChangeCallback interface {
   118  	OnChange(identityAddress string, status string)
   119  }
   120  
   121  // RegisterIdentityRegistrationChangeCallback registers callback which is called on identity registration status change.
   122  func (mb *MobileNode) RegisterIdentityRegistrationChangeCallback(cb IdentityRegistrationChangeCallback) {
   123  	_ = mb.eventBus.SubscribeAsync(registry.AppTopicIdentityRegistration, func(e registry.AppEventIdentityRegistration) {
   124  		cb.OnChange(e.ID.Address, e.Status.String())
   125  	})
   126  }
   127  
   128  // ExportIdentity exports a given identity address encrypting it with the new passphrase.
   129  func (mb *MobileNode) ExportIdentity(identityAddress, newPassphrase string) ([]byte, error) {
   130  	data, err := mb.identityMover.Export(identityAddress, "", newPassphrase)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	return data, nil
   136  }
   137  
   138  // ImportIdentity import a given identity address given data (json as string) and the
   139  // current passphrase.
   140  //
   141  // Identity can only be imported if it is registered.
   142  func (mb *MobileNode) ImportIdentity(data []byte, passphrase string) (string, error) {
   143  	identity, err := mb.identityMover.Import(data, passphrase, "")
   144  	if err != nil {
   145  		return "", err
   146  	}
   147  
   148  	return identity.Address, nil
   149  }
   150  
   151  // IsFreeRegistrationEligible returns true if free registration is possible for a given identity.
   152  func (mb *MobileNode) IsFreeRegistrationEligible(identityAddress string) (bool, error) {
   153  	id := identity.FromAddress(identityAddress)
   154  	ok, err := mb.transactor.GetFreeRegistrationEligibility(id)
   155  	if err != nil {
   156  		return false, err
   157  	}
   158  
   159  	return ok, nil
   160  }
   161  
   162  // RegistrationTokenReward returns the reward amount for a given token.
   163  func (mb *MobileNode) RegistrationTokenReward(token string) (float64, error) {
   164  	reward, err := mb.affiliator.RegistrationTokenReward(token)
   165  	if err != nil {
   166  		return 0, err
   167  	}
   168  	if reward == nil {
   169  		return 0, errors.New("failed to return reward")
   170  	}
   171  
   172  	return crypto.BigMystToFloat(reward), nil
   173  }
   174  
   175  // MigrateHermes migrate from old to active Hermes
   176  func (mb *MobileNode) MigrateHermes(id string) error {
   177  	return mb.hermesMigrator.Start(id)
   178  }
   179  
   180  const (
   181  	// MigrationStatusRequired means new there is new Hermes and identity required to migrate to it
   182  	MigrationStatusRequired = "required"
   183  	// MigrationStatusFinished means migration to new Hermes finished or not needed
   184  	MigrationStatusFinished = "finished"
   185  )
   186  
   187  // MigrationStatusResponse represents status of the migration
   188  type MigrationStatusResponse struct {
   189  	Status MigrationStatus `json:"status"`
   190  }
   191  
   192  // MigrationStatus status of the migration
   193  type MigrationStatus = string
   194  
   195  // MigrateHermesStatus migrate from old to active Hermes
   196  func (mb *MobileNode) MigrateHermesStatus(id string) ([]byte, error) {
   197  	r, err := mb.hermesMigrator.IsMigrationRequired(id)
   198  	if err != nil {
   199  		return []byte{}, err
   200  	}
   201  
   202  	var status MigrationStatus
   203  	if r {
   204  		status = MigrationStatusRequired
   205  	} else {
   206  		status = MigrationStatusFinished
   207  	}
   208  
   209  	return json.Marshal(MigrationStatusResponse{Status: status})
   210  }