Add CreateAccount endpoint

This commit is contained in:
Andrea Maria Piana 2023-03-16 14:49:25 +00:00
parent 5d0e08ec7b
commit 3d2fd26d80
5 changed files with 961 additions and 2 deletions

View File

@ -1 +1 @@
0.138.5
0.138.6

819
api/defaults.go Normal file
View File

@ -0,0 +1,819 @@
package api
import (
"crypto/rand"
"encoding/json"
"math/big"
"github.com/google/uuid"
"github.com/status-im/status-go/account/generator"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/protocol/identity/alias"
"github.com/status-im/status-go/protocol/requests"
)
const pathWalletRoot = "m/44'/60'/0'/0"
const pathEIP1581 = "m/43'/60'/1581'"
const pathDefaultChat = pathEIP1581 + "/0'/0"
const pathDefaultWallet = pathWalletRoot + "/0"
var paths = []string{pathWalletRoot, pathEIP1581, pathDefaultChat, pathDefaultWallet}
func defaultSettings(generatedAccountInfo generator.GeneratedAccountInfo, derivedAddresses map[string]generator.AccountInfo, mnemonic *string) (*settings.Settings, error) {
chatKeyString := derivedAddresses[pathDefaultChat].PublicKey
settings := &settings.Settings{}
settings.KeyUID = generatedAccountInfo.KeyUID
settings.Address = types.HexToAddress(generatedAccountInfo.Address)
settings.WalletRootAddress = types.HexToAddress(derivedAddresses[pathWalletRoot].Address)
// Set chat key & name
name, err := alias.GenerateFromPublicKeyString(chatKeyString)
if err != nil {
return nil, err
}
settings.Name = name
settings.PublicKey = chatKeyString
settings.DappsAddress = types.HexToAddress(derivedAddresses[pathDefaultWallet].Address)
settings.EIP1581Address = types.HexToAddress(derivedAddresses[pathEIP1581].Address)
settings.Mnemonic = mnemonic
signingPhrase, err := buildSigningPhrase()
if err != nil {
return nil, err
}
settings.SigningPhrase = signingPhrase
settings.SendPushNotifications = true
settings.InstallationID = uuid.New().String()
settings.UseMailservers = true
settings.PreviewPrivacy = true
settings.Currency = "usd"
settings.ProfilePicturesVisibility = 1
settings.LinkPreviewRequestEnabled = true
visibleTokens := make(map[string][]string)
visibleTokens["mainnet"] = []string{"SNT"}
visibleTokensJSON, err := json.Marshal(visibleTokens)
if err != nil {
return nil, err
}
visibleTokenJSONRaw := json.RawMessage(visibleTokensJSON)
settings.WalletVisibleTokens = &visibleTokenJSONRaw
// TODO: fix this
networks := make([]map[string]string, 0)
networksJSON, err := json.Marshal(networks)
if err != nil {
return nil, err
}
networkRawMessage := json.RawMessage(networksJSON)
settings.Networks = &networkRawMessage
settings.CurrentNetwork = "mainnet_rpc"
return settings, nil
}
func defaultNodeConfig(installationID string, request *requests.CreateAccount) (*params.NodeConfig, error) {
// Set mainnet
nodeConfig := &params.NodeConfig{}
nodeConfig.NetworkID = 1
nodeConfig.LogEnabled = request.LogEnabled
nodeConfig.LogFile = request.LogFilePath
nodeConfig.LogLevel = "ERROR"
nodeConfig.DataDir = "/ethereum/mainnet_rpc"
if request.LogLevel != nil {
nodeConfig.LogLevel = *request.LogLevel
}
nodeConfig.APIModules = "wakuext,ext,waku"
nodeConfig.UpstreamConfig = params.UpstreamRPCConfig{
Enabled: true,
URL: "https://mainnet.infura.io/v3/800c641949d64d768a5070a1b0511938",
}
nodeConfig.Name = "StatusIM"
nodeConfig.Rendezvous = false
clusterConfig, err := params.LoadClusterConfigFromFleet("status.prod")
if err != nil {
return nil, err
}
nodeConfig.ClusterConfig = *clusterConfig
nodeConfig.NoDiscovery = true
nodeConfig.MaxPeers = 20
nodeConfig.MaxPendingPeers = 20
nodeConfig.WalletConfig = params.WalletConfig{Enabled: true}
nodeConfig.LocalNotificationsConfig = params.LocalNotificationsConfig{Enabled: true}
nodeConfig.BrowsersConfig = params.BrowsersConfig{Enabled: true}
nodeConfig.PermissionsConfig = params.PermissionsConfig{Enabled: true}
nodeConfig.MailserversConfig = params.MailserversConfig{Enabled: true}
nodeConfig.EnableNTPSync = true
nodes := []string{"enrtree://AOGECG2SPND25EEFMAJ5WF3KSGJNSGV356DSTL2YVLLZWIV6SAYBM@prod.nodes.status.im"}
nodeConfig.ClusterConfig.WakuNodes = nodes
nodeConfig.ClusterConfig.DiscV5BootstrapNodes = nodes
nodeConfig.WakuV2Config = params.WakuV2Config{
Enabled: true,
EnableDiscV5: true,
DiscoveryLimit: 20,
Host: "0.0.0.0",
AutoUpdate: true,
PeerExchange: true,
}
if request.WakuV2Nameserver != nil {
nodeConfig.WakuV2Config.Nameserver = *request.WakuV2Nameserver
}
nodeConfig.ShhextConfig = params.ShhextConfig{
BackupDisabledDataDir: request.BackupDisabledDataDir,
InstallationID: installationID,
MaxMessageDeliveryAttempts: 6,
MailServerConfirmations: true,
VerifyTransactionURL: "",
VerifyENSURL: "",
VerifyENSContractAddress: "",
VerifyTransactionChainID: 1,
DataSyncEnabled: true,
PFSEnabled: true,
}
if request.VerifyTransactionURL != nil {
nodeConfig.ShhextConfig.VerifyTransactionURL = *request.VerifyTransactionURL
}
if request.VerifyENSURL != nil {
nodeConfig.ShhextConfig.VerifyENSURL = *request.VerifyENSURL
}
if request.VerifyTransactionChainID != nil {
nodeConfig.ShhextConfig.VerifyTransactionChainID = *request.VerifyTransactionChainID
}
if request.VerifyENSContractAddress != nil {
nodeConfig.ShhextConfig.VerifyENSContractAddress = *request.VerifyENSContractAddress
}
if request.LogLevel != nil {
nodeConfig.LogLevel = *request.LogLevel
nodeConfig.LogEnabled = true
} else {
nodeConfig.LogEnabled = false
}
return nodeConfig, nil
}
func buildSigningPhrase() (string, error) {
length := big.NewInt(int64(len(dictionary)))
a, err := rand.Int(rand.Reader, length)
if err != nil {
return "", err
}
b, err := rand.Int(rand.Reader, length)
if err != nil {
return "", err
}
c, err := rand.Int(rand.Reader, length)
if err != nil {
return "", err
}
return dictionary[a.Int64()] + " " + dictionary[b.Int64()] + " " + dictionary[c.Int64()], nil
}
var dictionary = []string{
"acid",
"alto",
"apse",
"arch",
"area",
"army",
"atom",
"aunt",
"babe",
"baby",
"back",
"bail",
"bait",
"bake",
"ball",
"band",
"bank",
"barn",
"base",
"bass",
"bath",
"bead",
"beak",
"beam",
"bean",
"bear",
"beat",
"beef",
"beer",
"beet",
"bell",
"belt",
"bend",
"bike",
"bill",
"bird",
"bite",
"blow",
"blue",
"boar",
"boat",
"body",
"bolt",
"bomb",
"bone",
"book",
"boot",
"bore",
"boss",
"bowl",
"brow",
"bulb",
"bull",
"burn",
"bush",
"bust",
"cafe",
"cake",
"calf",
"call",
"calm",
"camp",
"cane",
"cape",
"card",
"care",
"carp",
"cart",
"case",
"cash",
"cast",
"cave",
"cell",
"cent",
"chap",
"chef",
"chin",
"chip",
"chop",
"chub",
"chug",
"city",
"clam",
"clef",
"clip",
"club",
"clue",
"coal",
"coat",
"code",
"coil",
"coin",
"coke",
"cold",
"colt",
"comb",
"cone",
"cook",
"cope",
"copy",
"cord",
"cork",
"corn",
"cost",
"crab",
"craw",
"crew",
"crib",
"crop",
"crow",
"curl",
"cyst",
"dame",
"dare",
"dark",
"dart",
"dash",
"data",
"date",
"dead",
"deal",
"dear",
"debt",
"deck",
"deep",
"deer",
"desk",
"dhow",
"diet",
"dill",
"dime",
"dirt",
"dish",
"disk",
"dock",
"doll",
"door",
"dory",
"drag",
"draw",
"drop",
"drug",
"drum",
"duck",
"dump",
"dust",
"duty",
"ease",
"east",
"eave",
"eddy",
"edge",
"envy",
"epee",
"exam",
"exit",
"face",
"fact",
"fail",
"fall",
"fame",
"fang",
"farm",
"fawn",
"fear",
"feed",
"feel",
"feet",
"file",
"fill",
"film",
"find",
"fine",
"fire",
"fish",
"flag",
"flat",
"flax",
"flow",
"foam",
"fold",
"font",
"food",
"foot",
"fork",
"form",
"fort",
"fowl",
"frog",
"fuel",
"full",
"gain",
"gale",
"galn",
"game",
"garb",
"gate",
"gear",
"gene",
"gift",
"girl",
"give",
"glad",
"glen",
"glue",
"glut",
"goal",
"goat",
"gold",
"golf",
"gong",
"good",
"gown",
"grab",
"gram",
"gray",
"grey",
"grip",
"grit",
"gyro",
"hail",
"hair",
"half",
"hall",
"hand",
"hang",
"harm",
"harp",
"hate",
"hawk",
"head",
"heat",
"heel",
"hell",
"helo",
"help",
"hemp",
"herb",
"hide",
"high",
"hill",
"hire",
"hive",
"hold",
"hole",
"home",
"hood",
"hoof",
"hook",
"hope",
"hops",
"horn",
"hose",
"host",
"hour",
"hunt",
"hurt",
"icon",
"idea",
"inch",
"iris",
"iron",
"item",
"jail",
"jeep",
"jeff",
"joey",
"join",
"joke",
"judo",
"jump",
"junk",
"jury",
"jute",
"kale",
"keep",
"kick",
"kill",
"kilt",
"kind",
"king",
"kiss",
"kite",
"knee",
"knot",
"lace",
"lack",
"lady",
"lake",
"lamb",
"lamp",
"land",
"lark",
"lava",
"lawn",
"lead",
"leaf",
"leek",
"lier",
"life",
"lift",
"lily",
"limo",
"line",
"link",
"lion",
"lisa",
"list",
"load",
"loaf",
"loan",
"lock",
"loft",
"long",
"look",
"loss",
"lout",
"love",
"luck",
"lung",
"lute",
"lynx",
"lyre",
"maid",
"mail",
"main",
"make",
"male",
"mall",
"manx",
"many",
"mare",
"mark",
"mask",
"mass",
"mate",
"math",
"meal",
"meat",
"meet",
"menu",
"mess",
"mice",
"midi",
"mile",
"milk",
"mime",
"mind",
"mine",
"mini",
"mint",
"miss",
"mist",
"moat",
"mode",
"mole",
"mood",
"moon",
"most",
"moth",
"move",
"mule",
"mutt",
"nail",
"name",
"neat",
"neck",
"need",
"neon",
"nest",
"news",
"node",
"nose",
"note",
"oboe",
"okra",
"open",
"oval",
"oven",
"oxen",
"pace",
"pack",
"page",
"pail",
"pain",
"pair",
"palm",
"pard",
"park",
"part",
"pass",
"past",
"path",
"peak",
"pear",
"peen",
"peer",
"pelt",
"perp",
"pest",
"pick",
"pier",
"pike",
"pile",
"pimp",
"pine",
"ping",
"pink",
"pint",
"pipe",
"piss",
"pith",
"plan",
"play",
"plot",
"plow",
"poem",
"poet",
"pole",
"polo",
"pond",
"pony",
"poof",
"pool",
"port",
"post",
"prow",
"pull",
"puma",
"pump",
"pupa",
"push",
"quit",
"race",
"rack",
"raft",
"rage",
"rail",
"rain",
"rake",
"rank",
"rate",
"read",
"rear",
"reef",
"rent",
"rest",
"rice",
"rich",
"ride",
"ring",
"rise",
"risk",
"road",
"robe",
"rock",
"role",
"roll",
"roof",
"room",
"root",
"rope",
"rose",
"ruin",
"rule",
"rush",
"ruth",
"sack",
"safe",
"sage",
"sail",
"sale",
"salt",
"sand",
"sari",
"sash",
"save",
"scow",
"seal",
"seat",
"seed",
"self",
"sell",
"shed",
"shin",
"ship",
"shoe",
"shop",
"shot",
"show",
"sick",
"side",
"sign",
"silk",
"sill",
"silo",
"sing",
"sink",
"site",
"size",
"skin",
"sled",
"slip",
"smog",
"snob",
"snow",
"soap",
"sock",
"soda",
"sofa",
"soft",
"soil",
"song",
"soot",
"sort",
"soup",
"spot",
"spur",
"stag",
"star",
"stay",
"stem",
"step",
"stew",
"stop",
"stud",
"suck",
"suit",
"swan",
"swim",
"tail",
"tale",
"talk",
"tank",
"tard",
"task",
"taxi",
"team",
"tear",
"teen",
"tell",
"temp",
"tent",
"term",
"test",
"text",
"thaw",
"tile",
"till",
"time",
"tire",
"toad",
"toga",
"togs",
"tone",
"tool",
"toot",
"tote",
"tour",
"town",
"tram",
"tray",
"tree",
"trim",
"trip",
"tuba",
"tube",
"tuna",
"tune",
"turn",
"tutu",
"twig",
"type",
"unit",
"user",
"vane",
"vase",
"vast",
"veal",
"veil",
"vein",
"vest",
"vibe",
"view",
"vise",
"wait",
"wake",
"walk",
"wall",
"wash",
"wasp",
"wave",
"wear",
"weed",
"week",
"well",
"west",
"whip",
"wife",
"will",
"wind",
"wine",
"wing",
"wire",
"wish",
"wolf",
"wood",
"wool",
"word",
"work",
"worm",
"wrap",
"wren",
"yard",
"yarn",
"yawl",
"year",
"yoga",
"yoke",
"yurt",
"zinc",
"zone",
}

View File

@ -32,11 +32,13 @@ import (
"github.com/status-im/status-go/nodecfg"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/protocol"
"github.com/status-im/status-go/protocol/requests"
"github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/services/ext"
"github.com/status-im/status-go/services/personal"
"github.com/status-im/status-go/services/typeddata"
"github.com/status-im/status-go/signal"
"github.com/status-im/status-go/sqlite"
"github.com/status-im/status-go/transactions"
)
@ -432,6 +434,7 @@ func (b *GethStatusBackend) startNodeWithAccount(acc multiaccounts.Account, pass
err = b.StartNode(b.config)
if err != nil {
b.log.Info("failed to start node")
return err
}
@ -441,6 +444,7 @@ func (b *GethStatusBackend) startNodeWithAccount(acc multiaccounts.Account, pass
}
err = b.multiaccountsDB.UpdateAccountTimestamp(acc.KeyUID, time.Now().Unix())
if err != nil {
b.log.Info("failed to update account")
return err
}
@ -692,6 +696,88 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Accoun
return nil
}
func (b *GethStatusBackend) CreateAccountAndLogin(request *requests.CreateAccount) error {
if err := request.Validate(); err != nil {
return err
}
if err := b.accountManager.InitKeystore(filepath.Join(request.BackupDisabledDataDir, "keystore")); err != nil {
return err
}
b.UpdateRootDataDir(request.BackupDisabledDataDir)
err := b.OpenAccounts()
if err != nil {
b.log.Error("failed open accounts", err)
return err
}
generator := b.accountManager.AccountsGenerator()
generatedAccountInfos, err := generator.Generate(12, 1, "")
if err != nil {
return err
}
info := generatedAccountInfos[0]
derivedAddresses, err := generator.DeriveAddresses(info.ID, paths)
if err != nil {
return err
}
_, err = generator.StoreDerivedAccounts(info.ID, "", paths)
if err != nil {
return err
}
account := multiaccounts.Account{
KeyUID: info.KeyUID,
KDFIterations: sqlite.ReducedKDFIterationsNumber,
}
settings, err := defaultSettings(info, derivedAddresses, nil)
if err != nil {
return err
}
nodeConfig, err := defaultNodeConfig(settings.InstallationID, request)
if err != nil {
return err
}
walletDerivedAccount := derivedAddresses[pathDefaultWallet]
walletAccount := &accounts.Account{
PublicKey: types.Hex2Bytes(walletDerivedAccount.PublicKey),
KeyUID: info.KeyUID,
Address: types.HexToAddress(walletDerivedAccount.Address),
Color: "",
Wallet: true,
Path: pathDefaultWallet,
Name: "Ethereum account",
}
chatDerivedAccount := derivedAddresses[pathDefaultChat]
chatAccount := &accounts.Account{
PublicKey: types.Hex2Bytes(chatDerivedAccount.PublicKey),
KeyUID: info.KeyUID,
Address: types.HexToAddress(chatDerivedAccount.Address),
Name: settings.Name,
Chat: true,
Path: pathDefaultChat,
}
accounts := []*accounts.Account{walletAccount, chatAccount}
err = b.StartNodeWithAccountAndInitialConfig(account, "", *settings, nodeConfig, accounts)
if err != nil {
b.log.Error("start node", err)
return err
}
return nil
}
func (b *GethStatusBackend) ConvertToRegularAccount(mnemonic string, currPassword string, newPassword string) error {
mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ")
accountInfo, err := b.accountManager.AccountsGenerator().ImportMnemonic(mnemonicNoExtraSpaces, "")

View File

@ -29,12 +29,13 @@ import (
"github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/profiling"
protocol "github.com/status-im/status-go/protocol"
"github.com/status-im/status-go/protocol"
"github.com/status-im/status-go/protocol/common"
identityUtils "github.com/status-im/status-go/protocol/identity"
"github.com/status-im/status-go/protocol/identity/alias"
"github.com/status-im/status-go/protocol/identity/colorhash"
"github.com/status-im/status-go/protocol/identity/emojihash"
"github.com/status-im/status-go/protocol/requests"
"github.com/status-im/status-go/server"
"github.com/status-im/status-go/server/pairing"
"github.com/status-im/status-go/services/personal"
@ -261,6 +262,31 @@ func LoginWithConfig(accountData, password, configJSON string) string {
return makeJSONResponse(nil)
}
func CreateAccountAndLogin(requestJSON string) string {
var request requests.CreateAccount
err := json.Unmarshal([]byte(requestJSON), &request)
if err != nil {
return makeJSONResponse(err)
}
err = request.Validate()
if err != nil {
return makeJSONResponse(err)
}
api.RunAsync(func() error {
log.Debug("starting a node and creating config")
err := statusBackend.CreateAccountAndLogin(&request)
if err != nil {
log.Error("failed to create account", "error", err)
return err
}
log.Debug("started a node, and created account")
return nil
})
return makeJSONResponse(nil)
}
// SaveAccountAndLogin saves account in status-go database..
func SaveAccountAndLogin(accountData, password, settingsJSON, configJSON, subaccountData string) string {
var account multiaccounts.Account

View File

@ -8,12 +8,28 @@ var ErrCreateAccountInvalidDisplayName = errors.New("create-account: invalid dis
var ErrCreateAccountInvalidPassword = errors.New("create-account: invalid password")
var ErrCreateAccountInvalidImagePath = errors.New("create-account: invalid image path")
var ErrCreateAccountInvalidColor = errors.New("create-account: invalid color")
var ErrCreateAccountInvalidRootKeystoreDir = errors.New("create-account: invalid root keystore directory")
var ErrCreateAccountInvalidBackupDisabledDataDir = errors.New("create-account: invalid backup disabled data directory")
var ErrCreateAccountInvalidLogFilePath = errors.New("create-account: invalid log file path")
type CreateAccount struct {
DisplayName string `json:"displayName"`
Password string `json:"password"`
ImagePath string `json:"imagePath"`
Color string `json:"color"`
// RootKeystoreDir is the directory where keys are stored
RootKeystoreDir string `json:"rootKeystoreDir"`
// BackupDisabledDataDir is the directory where backup is disabled
BackupDisabledDataDir string `json:"backupDisabledDataDir"`
VerifyTransactionURL *string `json:"verifyTransactionURL"`
VerifyENSURL *string `json:"verifyENSURL"`
VerifyENSContractAddress *string `json:"verifyENSContractAddress"`
VerifyTransactionChainID *int64 `json:"verifyTransactionChainID"`
WakuV2Nameserver *string `json:"wakuV2Nameserver"`
LogLevel *string `json:"logLevel"`
LogFilePath string `json:"logFilePath"`
LogEnabled bool `json:"logEnabled"`
}
func (c *CreateAccount) Validate() error {
@ -34,6 +50,18 @@ func (c *CreateAccount) Validate() error {
return ErrCreateAccountInvalidColor
}
if len(c.RootKeystoreDir) == 0 {
return ErrCreateAccountInvalidRootKeystoreDir
}
if len(c.BackupDisabledDataDir) == 0 {
return ErrCreateAccountInvalidBackupDisabledDataDir
}
if len(c.LogFilePath) == 0 {
return ErrCreateAccountInvalidLogFilePath
}
return nil
}