github.com/status-im/status-go@v1.1.0/mobile/status.go (about) 1 package statusgo 2 3 import ( 4 "encoding/hex" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "unsafe" 9 10 validator "gopkg.in/go-playground/validator.v9" 11 12 "github.com/ethereum/go-ethereum/log" 13 "github.com/ethereum/go-ethereum/signer/core/apitypes" 14 15 "github.com/status-im/zxcvbn-go" 16 "github.com/status-im/zxcvbn-go/scoring" 17 18 abi_spec "github.com/status-im/status-go/abi-spec" 19 "github.com/status-im/status-go/account" 20 "github.com/status-im/status-go/api" 21 "github.com/status-im/status-go/api/multiformat" 22 "github.com/status-im/status-go/centralizedmetrics" 23 "github.com/status-im/status-go/centralizedmetrics/providers" 24 "github.com/status-im/status-go/eth-node/crypto" 25 "github.com/status-im/status-go/eth-node/types" 26 "github.com/status-im/status-go/exportlogs" 27 "github.com/status-im/status-go/extkeys" 28 "github.com/status-im/status-go/images" 29 "github.com/status-im/status-go/logutils" 30 "github.com/status-im/status-go/logutils/requestlog" 31 "github.com/status-im/status-go/multiaccounts" 32 "github.com/status-im/status-go/multiaccounts/accounts" 33 "github.com/status-im/status-go/multiaccounts/settings" 34 "github.com/status-im/status-go/params" 35 "github.com/status-im/status-go/profiling" 36 "github.com/status-im/status-go/protocol" 37 "github.com/status-im/status-go/protocol/common" 38 identityUtils "github.com/status-im/status-go/protocol/identity" 39 "github.com/status-im/status-go/protocol/identity/alias" 40 "github.com/status-im/status-go/protocol/identity/colorhash" 41 "github.com/status-im/status-go/protocol/identity/emojihash" 42 "github.com/status-im/status-go/protocol/requests" 43 "github.com/status-im/status-go/server" 44 "github.com/status-im/status-go/server/pairing" 45 "github.com/status-im/status-go/server/pairing/preflight" 46 "github.com/status-im/status-go/services/personal" 47 "github.com/status-im/status-go/services/typeddata" 48 "github.com/status-im/status-go/signal" 49 "github.com/status-im/status-go/transactions" 50 ) 51 52 type InitializeApplicationResponse struct { 53 Accounts []multiaccounts.Account `json:"accounts"` 54 CentralizedMetricsInfo *centralizedmetrics.MetricsInfo `json:"centralizedMetricsInfo"` 55 } 56 57 func InitializeApplication(requestJSON string) string { 58 return logAndCallString(initializeApplication, requestJSON) 59 } 60 61 func initializeApplication(requestJSON string) string { 62 var request requests.InitializeApplication 63 err := json.Unmarshal([]byte(requestJSON), &request) 64 if err != nil { 65 return makeJSONResponse(err) 66 } 67 err = request.Validate() 68 if err != nil { 69 return makeJSONResponse(err) 70 } 71 72 // initialize metrics 73 providers.MixpanelAppID = request.MixpanelAppID 74 providers.MixpanelToken = request.MixpanelToken 75 76 datadir := request.DataDir 77 78 statusBackend.UpdateRootDataDir(datadir) 79 err = statusBackend.OpenAccounts() 80 if err != nil { 81 return makeJSONResponse(err) 82 } 83 accs, err := statusBackend.GetAccounts() 84 if err != nil { 85 return makeJSONResponse(err) 86 } 87 centralizedMetricsInfo, err := statusBackend.CentralizedMetricsInfo() 88 if err != nil { 89 return makeJSONResponse(err) 90 } 91 response := &InitializeApplicationResponse{ 92 Accounts: accs, 93 CentralizedMetricsInfo: centralizedMetricsInfo, 94 } 95 data, err := json.Marshal(response) 96 if err != nil { 97 return makeJSONResponse(err) 98 } 99 return string(data) 100 } 101 102 func OpenAccounts(datadir string) string { 103 return logAndCallString(openAccounts, datadir) 104 } 105 106 // DEPRECATED: use InitializeApplication 107 // openAccounts opens database and returns accounts list. 108 func openAccounts(datadir string) string { 109 statusBackend.UpdateRootDataDir(datadir) 110 err := statusBackend.OpenAccounts() 111 if err != nil { 112 return makeJSONResponse(err) 113 } 114 accs, err := statusBackend.GetAccounts() 115 if err != nil { 116 return makeJSONResponse(err) 117 } 118 data, err := json.Marshal(accs) 119 if err != nil { 120 return makeJSONResponse(err) 121 } 122 return string(data) 123 } 124 125 func ExtractGroupMembershipSignatures(signaturePairsStr string) string { 126 return logAndCallString(extractGroupMembershipSignatures, signaturePairsStr) 127 } 128 129 // ExtractGroupMembershipSignatures extract public keys from tuples of content/signature. 130 func extractGroupMembershipSignatures(signaturePairsStr string) string { 131 var signaturePairs [][2]string 132 133 if err := json.Unmarshal([]byte(signaturePairsStr), &signaturePairs); err != nil { 134 return makeJSONResponse(err) 135 } 136 137 identities, err := statusBackend.ExtractGroupMembershipSignatures(signaturePairs) 138 if err != nil { 139 return makeJSONResponse(err) 140 } 141 142 data, err := json.Marshal(struct { 143 Identities []string `json:"identities"` 144 }{Identities: identities}) 145 if err != nil { 146 return makeJSONResponse(err) 147 } 148 149 return string(data) 150 } 151 152 func SignGroupMembership(content string) string { 153 return logAndCallString(signGroupMembership, content) 154 } 155 156 // signGroupMembership signs a string containing group membership information. 157 func signGroupMembership(content string) string { 158 signature, err := statusBackend.SignGroupMembership(content) 159 if err != nil { 160 return makeJSONResponse(err) 161 } 162 163 data, err := json.Marshal(struct { 164 Signature string `json:"signature"` 165 }{Signature: signature}) 166 if err != nil { 167 return makeJSONResponse(err) 168 } 169 170 return string(data) 171 } 172 173 func GetNodeConfig() string { 174 return logAndCallString(getNodeConfig) 175 } 176 177 // getNodeConfig returns the current config of the Status node 178 func getNodeConfig() string { 179 conf, err := statusBackend.GetNodeConfig() 180 if err != nil { 181 return makeJSONResponse(err) 182 } 183 184 respJSON, err := json.Marshal(conf) 185 if err != nil { 186 return makeJSONResponse(err) 187 } 188 189 return string(respJSON) 190 } 191 192 func ValidateNodeConfig(configJSON string) string { 193 return logAndCallString(validateNodeConfig, configJSON) 194 } 195 196 // validateNodeConfig validates config for the Status node. 197 func validateNodeConfig(configJSON string) string { 198 var resp APIDetailedResponse 199 200 _, err := params.NewConfigFromJSON(configJSON) 201 202 // Convert errors to APIDetailedResponse 203 switch err := err.(type) { 204 case validator.ValidationErrors: 205 resp = APIDetailedResponse{ 206 Message: "validation: validation failed", 207 FieldErrors: make([]APIFieldError, len(err)), 208 } 209 210 for i, ve := range err { 211 resp.FieldErrors[i] = APIFieldError{ 212 Parameter: ve.Namespace(), 213 Errors: []APIError{ 214 { 215 Message: fmt.Sprintf("field validation failed on the '%s' tag", ve.Tag()), 216 }, 217 }, 218 } 219 } 220 case error: 221 resp = APIDetailedResponse{ 222 Message: fmt.Sprintf("validation: %s", err.Error()), 223 } 224 case nil: 225 resp = APIDetailedResponse{ 226 Status: true, 227 } 228 } 229 230 respJSON, err := json.Marshal(resp) 231 if err != nil { 232 return makeJSONResponse(err) 233 } 234 235 return string(respJSON) 236 } 237 238 func ResetChainData() string { 239 return logAndCallString(resetChainData) 240 } 241 242 // resetChainData removes chain data from data directory. 243 func resetChainData() string { 244 api.RunAsync(statusBackend.ResetChainData) 245 return makeJSONResponse(nil) 246 } 247 248 func CallRPC(inputJSON string) string { 249 return logAndCallString(callRPC, inputJSON) 250 } 251 252 // callRPC calls public APIs via RPC. 253 func callRPC(inputJSON string) string { 254 resp, err := statusBackend.CallRPC(inputJSON) 255 if err != nil { 256 return makeJSONResponse(err) 257 } 258 return resp 259 } 260 261 func CallPrivateRPC(inputJSON string) string { 262 return logAndCallString(callPrivateRPC, inputJSON) 263 } 264 265 // callPrivateRPC calls both public and private APIs via RPC. 266 func callPrivateRPC(inputJSON string) string { 267 resp, err := statusBackend.CallPrivateRPC(inputJSON) 268 if err != nil { 269 return makeJSONResponse(err) 270 } 271 return resp 272 } 273 274 func VerifyAccountPassword(keyStoreDir, address, password string) string { 275 return logAndCallString(verifyAccountPassword, keyStoreDir, address, password) 276 } 277 278 // verifyAccountPassword verifies account password. 279 func verifyAccountPassword(keyStoreDir, address, password string) string { 280 _, err := statusBackend.AccountManager().VerifyAccountPassword(keyStoreDir, address, password) 281 return makeJSONResponse(err) 282 } 283 284 func VerifyDatabasePassword(keyUID, password string) string { 285 return logAndCallString(verifyDatabasePassword, keyUID, password) 286 } 287 288 // verifyDatabasePassword verifies database password. 289 func verifyDatabasePassword(keyUID, password string) string { 290 err := statusBackend.VerifyDatabasePassword(keyUID, password) 291 return makeJSONResponse(err) 292 } 293 294 func MigrateKeyStoreDir(accountData, password, oldDir, newDir string) string { 295 return logAndCallString(migrateKeyStoreDir, accountData, password, oldDir, newDir) 296 } 297 298 // migrateKeyStoreDir migrates key files to a new directory 299 func migrateKeyStoreDir(accountData, password, oldDir, newDir string) string { 300 var account multiaccounts.Account 301 err := json.Unmarshal([]byte(accountData), &account) 302 if err != nil { 303 return makeJSONResponse(err) 304 } 305 306 err = statusBackend.MigrateKeyStoreDir(account, password, oldDir, newDir) 307 return makeJSONResponse(err) 308 } 309 310 // login deprecated as Login and LoginWithConfig are deprecated 311 func login(accountData, password, configJSON string) error { 312 var account multiaccounts.Account 313 err := json.Unmarshal([]byte(accountData), &account) 314 if err != nil { 315 return err 316 } 317 318 var conf params.NodeConfig 319 if configJSON != "" { 320 err = json.Unmarshal([]byte(configJSON), &conf) 321 if err != nil { 322 return err 323 } 324 } 325 326 api.RunAsync(func() error { 327 log.Debug("start a node with account", "key-uid", account.KeyUID) 328 err := statusBackend.UpdateNodeConfigFleet(account, password, &conf) 329 if err != nil { 330 log.Error("failed to update node config fleet", "key-uid", account.KeyUID, "error", err) 331 return statusBackend.LoggedIn(account.KeyUID, err) 332 } 333 334 err = statusBackend.StartNodeWithAccount(account, password, &conf, nil) 335 if err != nil { 336 log.Error("failed to start a node", "key-uid", account.KeyUID, "error", err) 337 return err 338 } 339 log.Debug("started a node with", "key-uid", account.KeyUID) 340 return nil 341 }) 342 343 return nil 344 } 345 346 // Login loads a key file (for a given address), tries to decrypt it using the password, 347 // to verify ownership if verified, purges all the previous identities from Whisper, 348 // and injects verified key as shh identity. 349 // 350 // Deprecated: Use LoginAccount instead. 351 func Login(accountData, password string) string { 352 err := login(accountData, password, "") 353 if err != nil { 354 return makeJSONResponse(err) 355 } 356 return makeJSONResponse(nil) 357 } 358 359 // LoginWithConfig loads a key file (for a given address), tries to decrypt it using the password, 360 // to verify ownership if verified, purges all the previous identities from Whisper, 361 // and injects verified key as shh identity. It then updates the accounts node db configuration 362 // mergin the values received in the configJSON parameter 363 // 364 // Deprecated: Use LoginAccount instead. 365 func LoginWithConfig(accountData, password, configJSON string) string { 366 err := login(accountData, password, configJSON) 367 if err != nil { 368 return makeJSONResponse(err) 369 } 370 return makeJSONResponse(nil) 371 } 372 373 func CreateAccountAndLogin(requestJSON string) string { 374 return logAndCallString(createAccountAndLogin, requestJSON) 375 } 376 377 func createAccountAndLogin(requestJSON string) string { 378 var request requests.CreateAccount 379 err := json.Unmarshal([]byte(requestJSON), &request) 380 if err != nil { 381 return makeJSONResponse(err) 382 } 383 384 err = request.Validate(&requests.CreateAccountValidation{ 385 AllowEmptyDisplayName: false, 386 }) 387 if err != nil { 388 return makeJSONResponse(err) 389 } 390 391 api.RunAsync(func() error { 392 log.Debug("starting a node and creating config") 393 _, err := statusBackend.CreateAccountAndLogin(&request) 394 if err != nil { 395 log.Error("failed to create account", "error", err) 396 return err 397 } 398 log.Debug("started a node, and created account") 399 return nil 400 }) 401 return makeJSONResponse(nil) 402 } 403 404 func LoginAccount(requestJSON string) string { 405 return logAndCallString(loginAccount, requestJSON) 406 } 407 408 func loginAccount(requestJSON string) string { 409 var request requests.Login 410 err := json.Unmarshal([]byte(requestJSON), &request) 411 if err != nil { 412 return makeJSONResponse(err) 413 } 414 415 err = request.Validate() 416 if err != nil { 417 return makeJSONResponse(err) 418 } 419 420 api.RunAsync(func() error { 421 err := statusBackend.LoginAccount(&request) 422 if err != nil { 423 log.Error("loginAccount failed", "error", err) 424 return err 425 } 426 log.Debug("loginAccount started node") 427 return nil 428 }) 429 return makeJSONResponse(nil) 430 } 431 432 func RestoreAccountAndLogin(requestJSON string) string { 433 return logAndCallString(restoreAccountAndLogin, requestJSON) 434 } 435 436 func restoreAccountAndLogin(requestJSON string) string { 437 var request requests.RestoreAccount 438 err := json.Unmarshal([]byte(requestJSON), &request) 439 if err != nil { 440 return makeJSONResponse(err) 441 } 442 443 err = request.Validate() 444 if err != nil { 445 return makeJSONResponse(err) 446 } 447 448 api.RunAsync(func() error { 449 log.Debug("starting a node and restoring account") 450 451 if request.Keycard != nil { 452 _, err = statusBackend.RestoreKeycardAccountAndLogin(&request) 453 } else { 454 _, err = statusBackend.RestoreAccountAndLogin(&request) 455 } 456 457 if err != nil { 458 log.Error("failed to restore account", "error", err) 459 return err 460 } 461 log.Debug("started a node, and restored account") 462 return nil 463 }) 464 465 return makeJSONResponse(nil) 466 } 467 468 // SaveAccountAndLogin saves account in status-go database. 469 // Deprecated: Use CreateAccountAndLogin instead. 470 func SaveAccountAndLogin(accountData, password, settingsJSON, configJSON, subaccountData string) string { 471 var account multiaccounts.Account 472 err := json.Unmarshal([]byte(accountData), &account) 473 if err != nil { 474 return makeJSONResponse(err) 475 } 476 var settings settings.Settings 477 err = json.Unmarshal([]byte(settingsJSON), &settings) 478 if err != nil { 479 return makeJSONResponse(err) 480 } 481 482 if *settings.Mnemonic != "" { 483 settings.MnemonicWasNotShown = true 484 } 485 486 var conf params.NodeConfig 487 err = json.Unmarshal([]byte(configJSON), &conf) 488 if err != nil { 489 return makeJSONResponse(err) 490 } 491 var subaccs []*accounts.Account 492 err = json.Unmarshal([]byte(subaccountData), &subaccs) 493 if err != nil { 494 return makeJSONResponse(err) 495 } 496 497 api.RunAsync(func() error { 498 log.Debug("starting a node, and saving account with configuration", "key-uid", account.KeyUID) 499 err := statusBackend.StartNodeWithAccountAndInitialConfig(account, password, settings, &conf, subaccs, nil) 500 if err != nil { 501 log.Error("failed to start node and save account", "key-uid", account.KeyUID, "error", err) 502 return err 503 } 504 log.Debug("started a node, and saved account", "key-uid", account.KeyUID) 505 return nil 506 }) 507 return makeJSONResponse(nil) 508 } 509 510 func DeleteMultiaccount(keyUID, keyStoreDir string) string { 511 return logAndCallString(deleteMultiaccount, keyUID, keyStoreDir) 512 } 513 514 // deleteMultiaccount 515 func deleteMultiaccount(keyUID, keyStoreDir string) string { 516 err := statusBackend.DeleteMultiaccount(keyUID, keyStoreDir) 517 return makeJSONResponse(err) 518 } 519 520 func DeleteImportedKey(address, password, keyStoreDir string) string { 521 return logAndCallString(deleteImportedKey, address, password, keyStoreDir) 522 } 523 524 // deleteImportedKey 525 func deleteImportedKey(address, password, keyStoreDir string) string { 526 err := statusBackend.DeleteImportedKey(address, password, keyStoreDir) 527 return makeJSONResponse(err) 528 } 529 530 func InitKeystore(keydir string) string { 531 return logAndCallString(initKeystore, keydir) 532 } 533 534 // initKeystore initialize keystore before doing any operations with keys. 535 func initKeystore(keydir string) string { 536 err := statusBackend.AccountManager().InitKeystore(keydir) 537 return makeJSONResponse(err) 538 } 539 540 // SaveAccountAndLoginWithKeycard saves account in status-go database. 541 // Deprecated: Use CreateAndAccountAndLogin with required keycard properties. 542 func SaveAccountAndLoginWithKeycard(accountData, password, settingsJSON, configJSON, subaccountData string, keyHex string) string { 543 var account multiaccounts.Account 544 err := json.Unmarshal([]byte(accountData), &account) 545 if err != nil { 546 return makeJSONResponse(err) 547 } 548 var settings settings.Settings 549 err = json.Unmarshal([]byte(settingsJSON), &settings) 550 if err != nil { 551 return makeJSONResponse(err) 552 } 553 var conf params.NodeConfig 554 err = json.Unmarshal([]byte(configJSON), &conf) 555 if err != nil { 556 return makeJSONResponse(err) 557 } 558 var subaccs []*accounts.Account 559 err = json.Unmarshal([]byte(subaccountData), &subaccs) 560 if err != nil { 561 return makeJSONResponse(err) 562 } 563 564 api.RunAsync(func() error { 565 log.Debug("starting a node, and saving account with configuration", "key-uid", account.KeyUID) 566 err := statusBackend.SaveAccountAndStartNodeWithKey(account, password, settings, &conf, subaccs, keyHex) 567 if err != nil { 568 log.Error("failed to start node and save account", "key-uid", account.KeyUID, "error", err) 569 return err 570 } 571 log.Debug("started a node, and saved account", "key-uid", account.KeyUID) 572 return nil 573 }) 574 return makeJSONResponse(nil) 575 } 576 577 // LoginWithKeycard initializes an account with a chat key and encryption key used for PFS. 578 // It purges all the previous identities from Whisper, and injects the key as shh identity. 579 // Deprecated: Use LoginAccount instead. 580 func LoginWithKeycard(accountData, password, keyHex string, configJSON string) string { 581 var account multiaccounts.Account 582 err := json.Unmarshal([]byte(accountData), &account) 583 if err != nil { 584 return makeJSONResponse(err) 585 } 586 var conf params.NodeConfig 587 err = json.Unmarshal([]byte(configJSON), &conf) 588 if err != nil { 589 return makeJSONResponse(err) 590 } 591 api.RunAsync(func() error { 592 log.Debug("start a node with account", "key-uid", account.KeyUID) 593 err := statusBackend.StartNodeWithKey(account, password, keyHex, &conf) 594 if err != nil { 595 log.Error("failed to start a node", "key-uid", account.KeyUID, "error", err) 596 return err 597 } 598 log.Debug("started a node with", "key-uid", account.KeyUID) 599 return nil 600 }) 601 return makeJSONResponse(nil) 602 } 603 604 func Logout() string { 605 return logAndCallString(logout) 606 } 607 608 // logout is equivalent to clearing whisper identities. 609 func logout() string { 610 return makeJSONResponse(statusBackend.Logout()) 611 } 612 613 func SignMessage(rpcParams string) string { 614 return logAndCallString(signMessage, rpcParams) 615 } 616 617 // signMessage unmarshals rpc params {data, address, password} and 618 // passes them onto backend.SignMessage. 619 func signMessage(rpcParams string) string { 620 var params personal.SignParams 621 err := json.Unmarshal([]byte(rpcParams), ¶ms) 622 if err != nil { 623 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 624 } 625 result, err := statusBackend.SignMessage(params) 626 return prepareJSONResponse(result.String(), err) 627 } 628 629 // SignTypedData unmarshall data into TypedData, validate it and signs with selected account, 630 // if password matches selected account. 631 // 632 //export SignTypedData 633 func SignTypedData(data, address, password string) string { 634 return logAndCallString(signTypedData, data, address, password) 635 } 636 637 func signTypedData(data, address, password string) string { 638 var typed typeddata.TypedData 639 err := json.Unmarshal([]byte(data), &typed) 640 if err != nil { 641 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 642 } 643 if err := typed.Validate(); err != nil { 644 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 645 } 646 result, err := statusBackend.SignTypedData(typed, address, password) 647 return prepareJSONResponse(result.String(), err) 648 } 649 650 // HashTypedData unmarshalls data into TypedData, validates it and hashes it. 651 // 652 //export HashTypedData 653 func HashTypedData(data string) string { 654 return logAndCallString(hashTypedData, data) 655 } 656 657 func hashTypedData(data string) string { 658 var typed typeddata.TypedData 659 err := json.Unmarshal([]byte(data), &typed) 660 if err != nil { 661 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 662 } 663 if err := typed.Validate(); err != nil { 664 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 665 } 666 result, err := statusBackend.HashTypedData(typed) 667 return prepareJSONResponse(result.String(), err) 668 } 669 670 // SignTypedDataV4 unmarshall data into TypedData, validate it and signs with selected account, 671 // if password matches selected account. 672 // 673 //export SignTypedDataV4 674 func SignTypedDataV4(data, address, password string) string { 675 return logAndCallString(signTypedDataV4, data, address, password) 676 } 677 678 func signTypedDataV4(data, address, password string) string { 679 var typed apitypes.TypedData 680 err := json.Unmarshal([]byte(data), &typed) 681 if err != nil { 682 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 683 } 684 result, err := statusBackend.SignTypedDataV4(typed, address, password) 685 return prepareJSONResponse(result.String(), err) 686 } 687 688 // HashTypedDataV4 unmarshalls data into TypedData, validates it and hashes it. 689 // 690 //export HashTypedDataV4 691 func HashTypedDataV4(data string) string { 692 return logAndCallString(hashTypedDataV4, data) 693 } 694 695 func hashTypedDataV4(data string) string { 696 var typed apitypes.TypedData 697 err := json.Unmarshal([]byte(data), &typed) 698 if err != nil { 699 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 700 } 701 result, err := statusBackend.HashTypedDataV4(typed) 702 return prepareJSONResponse(result.String(), err) 703 } 704 705 func Recover(rpcParams string) string { 706 return logAndCallString(recoverWithRPCParams, rpcParams) 707 } 708 709 // recoverWithRPCParams unmarshals rpc params {signDataString, signedData} and passes 710 // them onto backend. 711 func recoverWithRPCParams(rpcParams string) string { 712 var params personal.RecoverParams 713 err := json.Unmarshal([]byte(rpcParams), ¶ms) 714 if err != nil { 715 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 716 } 717 addr, err := statusBackend.Recover(params) 718 return prepareJSONResponse(addr.String(), err) 719 } 720 721 func SendTransactionWithChainID(chainID int, txArgsJSON, password string) string { 722 return logAndCallString(sendTransactionWithChainID, chainID, txArgsJSON, password) 723 } 724 725 // sendTransactionWithChainID converts RPC args and calls backend.SendTransactionWithChainID. 726 func sendTransactionWithChainID(chainID int, txArgsJSON, password string) string { 727 var params transactions.SendTxArgs 728 err := json.Unmarshal([]byte(txArgsJSON), ¶ms) 729 if err != nil { 730 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 731 } 732 hash, err := statusBackend.SendTransactionWithChainID(uint64(chainID), params, password) 733 code := codeUnknown 734 if c, ok := errToCodeMap[err]; ok { 735 code = c 736 } 737 return prepareJSONResponseWithCode(hash.String(), err, code) 738 } 739 740 func SendTransaction(txArgsJSON, password string) string { 741 return logAndCallString(sendTransaction, txArgsJSON, password) 742 } 743 744 // sendTransaction converts RPC args and calls backend.SendTransaction. 745 func sendTransaction(txArgsJSON, password string) string { 746 var params transactions.SendTxArgs 747 err := json.Unmarshal([]byte(txArgsJSON), ¶ms) 748 if err != nil { 749 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 750 } 751 hash, err := statusBackend.SendTransaction(params, password) 752 code := codeUnknown 753 if c, ok := errToCodeMap[err]; ok { 754 code = c 755 } 756 return prepareJSONResponseWithCode(hash.String(), err, code) 757 } 758 759 func SendTransactionWithSignature(txArgsJSON, sigString string) string { 760 return logAndCallString(sendTransactionWithSignature, txArgsJSON, sigString) 761 } 762 763 // sendTransactionWithSignature converts RPC args and calls backend.SendTransactionWithSignature 764 func sendTransactionWithSignature(txArgsJSON, sigString string) string { 765 var params transactions.SendTxArgs 766 err := json.Unmarshal([]byte(txArgsJSON), ¶ms) 767 if err != nil { 768 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 769 } 770 771 sig, err := hex.DecodeString(sigString) 772 if err != nil { 773 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 774 } 775 776 hash, err := statusBackend.SendTransactionWithSignature(params, sig) 777 code := codeUnknown 778 if c, ok := errToCodeMap[err]; ok { 779 code = c 780 } 781 return prepareJSONResponseWithCode(hash.String(), err, code) 782 } 783 784 func HashTransaction(txArgsJSON string) string { 785 return logAndCallString(hashTransaction, txArgsJSON) 786 } 787 788 // hashTransaction validate the transaction and returns new txArgs and the transaction hash. 789 func hashTransaction(txArgsJSON string) string { 790 var params transactions.SendTxArgs 791 err := json.Unmarshal([]byte(txArgsJSON), ¶ms) 792 if err != nil { 793 return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) 794 } 795 796 newTxArgs, hash, err := statusBackend.HashTransaction(params) 797 code := codeUnknown 798 if c, ok := errToCodeMap[err]; ok { 799 code = c 800 } 801 802 result := struct { 803 Transaction transactions.SendTxArgs `json:"transaction"` 804 Hash types.Hash `json:"hash"` 805 }{ 806 Transaction: newTxArgs, 807 Hash: hash, 808 } 809 810 return prepareJSONResponseWithCode(result, err, code) 811 } 812 813 func HashMessage(message string) string { 814 return logAndCallString(hashMessage, message) 815 } 816 817 // hashMessage calculates the hash of a message to be safely signed by the keycard 818 // The hash is calulcated as 819 // 820 // keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). 821 // 822 // This gives context to the signed message and prevents signing of transactions. 823 func hashMessage(message string) string { 824 hash, err := api.HashMessage(message) 825 code := codeUnknown 826 if c, ok := errToCodeMap[err]; ok { 827 code = c 828 } 829 return prepareJSONResponseWithCode(fmt.Sprintf("0x%x", hash), err, code) 830 } 831 832 func StartCPUProfile(dataDir string) string { 833 return logAndCallString(startCPUProfile, dataDir) 834 } 835 836 // startCPUProfile runs pprof for CPU. 837 func startCPUProfile(dataDir string) string { 838 err := profiling.StartCPUProfile(dataDir) 839 return makeJSONResponse(err) 840 } 841 842 func StopCPUProfiling() string { 843 return logAndCallString(stopCPUProfiling) 844 } 845 846 // stopCPUProfiling stops pprof for cpu. 847 func stopCPUProfiling() string { //nolint: deadcode 848 err := profiling.StopCPUProfile() 849 return makeJSONResponse(err) 850 } 851 852 func WriteHeapProfile(dataDir string) string { 853 return logAndCallString(writeHeapProfile, dataDir) 854 } 855 856 // writeHeapProfile starts pprof for heap 857 func writeHeapProfile(dataDir string) string { //nolint: deadcode 858 err := profiling.WriteHeapFile(dataDir) 859 return makeJSONResponse(err) 860 } 861 862 func makeJSONResponse(err error) string { 863 errString := "" 864 if err != nil { 865 log.Error("error in makeJSONResponse", "error", err) 866 errString = err.Error() 867 } 868 869 out := APIResponse{ 870 Error: errString, 871 } 872 outBytes, _ := json.Marshal(out) 873 874 return string(outBytes) 875 } 876 877 func AddPeer(enode string) string { 878 return logAndCallString(addPeer, enode) 879 } 880 881 // addPeer adds an enode as a peer. 882 func addPeer(enode string) string { 883 err := statusBackend.StatusNode().AddPeer(enode) 884 return makeJSONResponse(err) 885 } 886 887 func ConnectionChange(typ string, expensive int) { 888 logAndCall(connectionChange, typ, expensive) 889 } 890 891 // connectionChange handles network state changes as reported 892 // by ReactNative (see https://facebook.github.io/react-native/docs/netinfo.html) 893 func connectionChange(typ string, expensive int) { 894 statusBackend.ConnectionChange(typ, expensive == 1) 895 } 896 897 func AppStateChange(state string) { 898 logAndCall(appStateChange, state) 899 } 900 901 // appStateChange handles app state changes (background/foreground). 902 func appStateChange(state string) { 903 statusBackend.AppStateChange(state) 904 } 905 906 func StartLocalNotifications() string { 907 return logAndCallString(startLocalNotifications) 908 } 909 910 // startLocalNotifications 911 func startLocalNotifications() string { 912 err := statusBackend.StartLocalNotifications() 913 return makeJSONResponse(err) 914 } 915 916 func StopLocalNotifications() string { 917 return logAndCallString(stopLocalNotifications) 918 } 919 920 // stopLocalNotifications 921 func stopLocalNotifications() string { 922 err := statusBackend.StopLocalNotifications() 923 return makeJSONResponse(err) 924 } 925 926 func SetMobileSignalHandler(handler SignalHandler) { 927 logAndCall(setMobileSignalHandler, handler) 928 } 929 930 // setMobileSignalHandler setup geth callback to notify about new signal 931 // used for gomobile builds 932 func setMobileSignalHandler(handler SignalHandler) { 933 signal.SetMobileSignalHandler(func(data []byte) { 934 if len(data) > 0 { 935 handler.HandleSignal(string(data)) 936 } 937 }) 938 } 939 940 func SetSignalEventCallback(cb unsafe.Pointer) { 941 logAndCall(setSignalEventCallback, cb) 942 } 943 944 // setSignalEventCallback setup geth callback to notify about new signal 945 func setSignalEventCallback(cb unsafe.Pointer) { 946 signal.SetSignalEventCallback(cb) 947 } 948 949 // ExportNodeLogs reads current node log and returns content to a caller. 950 // 951 //export ExportNodeLogs 952 func ExportNodeLogs() string { 953 return logAndCallString(exportNodeLogs) 954 } 955 956 func exportNodeLogs() string { 957 node := statusBackend.StatusNode() 958 if node == nil { 959 return makeJSONResponse(errors.New("node is not running")) 960 } 961 config := node.Config() 962 if config == nil { 963 return makeJSONResponse(errors.New("config and log file are not available")) 964 } 965 data, err := json.Marshal(exportlogs.ExportFromBaseFile(config.LogFile)) 966 if err != nil { 967 return makeJSONResponse(fmt.Errorf("error marshalling to json: %v", err)) 968 } 969 return string(data) 970 } 971 972 func SignHash(hexEncodedHash string) string { 973 return logAndCallString(signHash, hexEncodedHash) 974 } 975 976 // signHash exposes vanilla ECDSA signing required for Swarm messages 977 func signHash(hexEncodedHash string) string { 978 hexEncodedSignature, err := statusBackend.SignHash(hexEncodedHash) 979 if err != nil { 980 return makeJSONResponse(err) 981 } 982 return hexEncodedSignature 983 } 984 985 func GenerateAlias(pk string) string { 986 return logAndCallString(generateAlias, pk) 987 } 988 989 func generateAlias(pk string) string { 990 // We ignore any error, empty string is considered an error 991 name, _ := protocol.GenerateAlias(pk) 992 return name 993 } 994 995 func IsAlias(value string) string { 996 return logAndCallString(isAlias, value) 997 } 998 999 func isAlias(value string) string { 1000 return prepareJSONResponse(alias.IsAlias(value), nil) 1001 } 1002 1003 func Identicon(pk string) string { 1004 return logAndCallString(identicon, pk) 1005 } 1006 1007 func identicon(pk string) string { 1008 // We ignore any error, empty string is considered an error 1009 identicon, _ := protocol.Identicon(pk) 1010 return identicon 1011 } 1012 1013 func EmojiHash(pk string) string { 1014 return logAndCallString(emojiHash, pk) 1015 } 1016 1017 func emojiHash(pk string) string { 1018 return prepareJSONResponse(emojihash.GenerateFor(pk)) 1019 } 1020 1021 func ColorHash(pk string) string { 1022 return logAndCallString(colorHash, pk) 1023 } 1024 1025 func colorHash(pk string) string { 1026 return prepareJSONResponse(colorhash.GenerateFor(pk)) 1027 } 1028 1029 func ColorID(pk string) string { 1030 return logAndCallString(colorID, pk) 1031 } 1032 1033 func colorID(pk string) string { 1034 return prepareJSONResponse(identityUtils.ToColorID(pk)) 1035 } 1036 1037 func ValidateMnemonic(mnemonic string) string { 1038 return logAndCallString(validateMnemonic, mnemonic) 1039 } 1040 1041 func validateMnemonic(mnemonic string) string { 1042 m := extkeys.NewMnemonic() 1043 err := m.ValidateMnemonic(mnemonic, extkeys.Language(0)) 1044 if err != nil { 1045 return makeJSONResponse(err) 1046 } 1047 1048 keyUID, err := statusBackend.GetKeyUIDByMnemonic(mnemonic) 1049 if err != nil { 1050 return makeJSONResponse(err) 1051 } 1052 1053 response := &APIKeyUIDResponse{KeyUID: keyUID} 1054 data, err := json.Marshal(response) 1055 if err != nil { 1056 return makeJSONResponse(err) 1057 } 1058 return string(data) 1059 } 1060 1061 func DecompressPublicKey(key string) string { 1062 return logAndCallString(decompressPublicKey, key) 1063 } 1064 1065 // decompressPublicKey decompresses 33-byte compressed format to uncompressed 65-byte format. 1066 func decompressPublicKey(key string) string { 1067 decoded, err := types.DecodeHex(key) 1068 if err != nil { 1069 return makeJSONResponse(err) 1070 } 1071 const compressionBytesNumber = 33 1072 if len(decoded) != compressionBytesNumber { 1073 return makeJSONResponse(errors.New("key is not 33 bytes long")) 1074 } 1075 pubKey, err := crypto.DecompressPubkey(decoded) 1076 if err != nil { 1077 return makeJSONResponse(err) 1078 } 1079 return types.EncodeHex(crypto.FromECDSAPub(pubKey)) 1080 } 1081 1082 func CompressPublicKey(key string) string { 1083 return logAndCallString(compressPublicKey, key) 1084 } 1085 1086 // compressPublicKey compresses uncompressed 65-byte format to 33-byte compressed format. 1087 func compressPublicKey(key string) string { 1088 pubKey, err := common.HexToPubkey(key) 1089 if err != nil { 1090 return makeJSONResponse(err) 1091 } 1092 return types.EncodeHex(crypto.CompressPubkey(pubKey)) 1093 } 1094 1095 func SerializeLegacyKey(key string) string { 1096 return logAndCallString(serializeLegacyKey, key) 1097 } 1098 1099 // serializeLegacyKey compresses an old format public key (0x04...) to the new one zQ... 1100 func serializeLegacyKey(key string) string { 1101 cpk, err := multiformat.SerializeLegacyKey(key) 1102 if err != nil { 1103 return makeJSONResponse(err) 1104 } 1105 return cpk 1106 } 1107 1108 func MultiformatSerializePublicKey(key, outBase string) string { 1109 return logAndCallString(multiformatSerializePublicKey, key, outBase) 1110 } 1111 1112 // SerializePublicKey compresses an uncompressed multibase encoded multicodec identified EC public key 1113 // For details on usage see specs https://specs.status.im/spec/2#public-key-serialization 1114 func multiformatSerializePublicKey(key, outBase string) string { 1115 cpk, err := multiformat.SerializePublicKey(key, outBase) 1116 if err != nil { 1117 return makeJSONResponse(err) 1118 } 1119 return cpk 1120 } 1121 1122 func MultiformatDeserializePublicKey(key, outBase string) string { 1123 return logAndCallString(multiformatDeserializePublicKey, key, outBase) 1124 } 1125 1126 // DeserializePublicKey decompresses a compressed multibase encoded multicodec identified EC public key 1127 // For details on usage see specs https://specs.status.im/spec/2#public-key-serialization 1128 func multiformatDeserializePublicKey(key, outBase string) string { 1129 pk, err := multiformat.DeserializePublicKey(key, outBase) 1130 if err != nil { 1131 return makeJSONResponse(err) 1132 } 1133 return pk 1134 } 1135 1136 func ExportUnencryptedDatabase(accountData, password, databasePath string) string { 1137 return logAndCallString(exportUnencryptedDatabase, accountData, password, databasePath) 1138 } 1139 1140 // exportUnencryptedDatabase exports the database unencrypted to the given path 1141 func exportUnencryptedDatabase(accountData, password, databasePath string) string { 1142 var account multiaccounts.Account 1143 err := json.Unmarshal([]byte(accountData), &account) 1144 if err != nil { 1145 return makeJSONResponse(err) 1146 } 1147 err = statusBackend.ExportUnencryptedDatabase(account, password, databasePath) 1148 return makeJSONResponse(err) 1149 } 1150 1151 func ImportUnencryptedDatabase(accountData, password, databasePath string) string { 1152 return logAndCallString(importUnencryptedDatabase, accountData, password, databasePath) 1153 } 1154 1155 // importUnencryptedDatabase imports the database unencrypted to the given directory 1156 func importUnencryptedDatabase(accountData, password, databasePath string) string { 1157 var account multiaccounts.Account 1158 err := json.Unmarshal([]byte(accountData), &account) 1159 if err != nil { 1160 return makeJSONResponse(err) 1161 } 1162 err = statusBackend.ImportUnencryptedDatabase(account, password, databasePath) 1163 return makeJSONResponse(err) 1164 } 1165 1166 func ChangeDatabasePassword(KeyUID, password, newPassword string) string { 1167 return logAndCallString(changeDatabasePassword, KeyUID, password, newPassword) 1168 } 1169 1170 // changeDatabasePassword changes the password of the database 1171 func changeDatabasePassword(KeyUID, password, newPassword string) string { 1172 err := statusBackend.ChangeDatabasePassword(KeyUID, password, newPassword) 1173 return makeJSONResponse(err) 1174 } 1175 1176 func ConvertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword string) string { 1177 return logAndCallString(convertToKeycardAccount, accountData, settingsJSON, keycardUID, password, newPassword) 1178 } 1179 1180 // convertToKeycardAccount converts the account to a keycard account 1181 func convertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword string) string { 1182 var account multiaccounts.Account 1183 err := json.Unmarshal([]byte(accountData), &account) 1184 if err != nil { 1185 return makeJSONResponse(err) 1186 } 1187 var settings settings.Settings 1188 err = json.Unmarshal([]byte(settingsJSON), &settings) 1189 if err != nil { 1190 return makeJSONResponse(err) 1191 } 1192 1193 err = statusBackend.ConvertToKeycardAccount(account, settings, keycardUID, password, newPassword) 1194 return makeJSONResponse(err) 1195 } 1196 1197 func ConvertToRegularAccount(mnemonic, currPassword, newPassword string) string { 1198 return logAndCallString(convertToRegularAccount, mnemonic, currPassword, newPassword) 1199 } 1200 1201 // convertToRegularAccount converts the account to a regular account 1202 func convertToRegularAccount(mnemonic, currPassword, newPassword string) string { 1203 err := statusBackend.ConvertToRegularAccount(mnemonic, currPassword, newPassword) 1204 return makeJSONResponse(err) 1205 } 1206 1207 func ImageServerTLSCert() string { 1208 cert, err := server.PublicMediaTLSCert() 1209 if err != nil { 1210 return makeJSONResponse(err) 1211 } 1212 return cert 1213 } 1214 1215 type GetPasswordStrengthRequest struct { 1216 Password string `json:"password"` 1217 UserInputs []string `json:"userInputs"` 1218 } 1219 1220 type PasswordScoreResponse struct { 1221 Score int `json:"score"` 1222 } 1223 1224 // GetPasswordStrength uses zxcvbn module and generates a JSON containing information about the quality of the given password 1225 // (Entropy, CrackTime, CrackTimeDisplay, Score, MatchSequence and CalcTime). 1226 // userInputs argument can be whatever list of strings like user's personal info or site-specific vocabulary that zxcvbn will 1227 // make use to determine the result. 1228 // For more details on usage see https://github.com/status-im/zxcvbn-go 1229 func GetPasswordStrength(paramsJSON string) string { 1230 var requestParams GetPasswordStrengthRequest 1231 1232 err := json.Unmarshal([]byte(paramsJSON), &requestParams) 1233 if err != nil { 1234 return makeJSONResponse(err) 1235 } 1236 1237 data, err := json.Marshal(zxcvbn.PasswordStrength(requestParams.Password, requestParams.UserInputs)) 1238 if err != nil { 1239 return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err)) 1240 } 1241 return string(data) 1242 } 1243 1244 // GetPasswordStrengthScore uses zxcvbn module and gets the score information about the given password. 1245 // userInputs argument can be whatever list of strings like user's personal info or site-specific vocabulary that zxcvbn will 1246 // make use to determine the result. 1247 // For more details on usage see https://github.com/status-im/zxcvbn-go 1248 func GetPasswordStrengthScore(paramsJSON string) string { 1249 var requestParams GetPasswordStrengthRequest 1250 var quality scoring.MinEntropyMatch 1251 1252 err := json.Unmarshal([]byte(paramsJSON), &requestParams) 1253 if err != nil { 1254 return makeJSONResponse(err) 1255 } 1256 1257 quality = zxcvbn.PasswordStrength(requestParams.Password, requestParams.UserInputs) 1258 1259 data, err := json.Marshal(PasswordScoreResponse{ 1260 Score: quality.Score, 1261 }) 1262 if err != nil { 1263 return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err)) 1264 } 1265 return string(data) 1266 } 1267 1268 type FleetDescription struct { 1269 DefaultFleet string `json:"defaultFleet"` 1270 Fleets map[string]map[string][]string `json:"fleets"` 1271 } 1272 1273 func Fleets() string { 1274 return logAndCallString(fleets) 1275 } 1276 1277 func fleets() string { 1278 fleets := FleetDescription{ 1279 DefaultFleet: api.DefaultFleet, 1280 Fleets: params.GetSupportedFleets(), 1281 } 1282 1283 data, err := json.Marshal(fleets) 1284 if err != nil { 1285 return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err)) 1286 } 1287 return string(data) 1288 } 1289 1290 func SwitchFleet(fleet string, configJSON string) string { 1291 return logAndCallString(switchFleet, fleet, configJSON) 1292 } 1293 1294 func switchFleet(fleet string, configJSON string) string { 1295 var conf params.NodeConfig 1296 if configJSON != "" { 1297 err := json.Unmarshal([]byte(configJSON), &conf) 1298 if err != nil { 1299 return makeJSONResponse(err) 1300 } 1301 } 1302 1303 clusterConfig, err := params.LoadClusterConfigFromFleet(fleet) 1304 if err != nil { 1305 return makeJSONResponse(err) 1306 } 1307 1308 conf.ClusterConfig.Fleet = fleet 1309 conf.ClusterConfig.ClusterID = clusterConfig.ClusterID 1310 1311 err = statusBackend.SwitchFleet(fleet, &conf) 1312 1313 return makeJSONResponse(err) 1314 } 1315 1316 func GenerateImages(filepath string, aX, aY, bX, bY int) string { 1317 iis, err := images.GenerateIdentityImages(filepath, aX, aY, bX, bY) 1318 if err != nil { 1319 return makeJSONResponse(err) 1320 } 1321 1322 data, err := json.Marshal(iis) 1323 if err != nil { 1324 return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err)) 1325 } 1326 return string(data) 1327 } 1328 1329 func LocalPairingPreflightOutboundCheck() string { 1330 return logAndCallString(localPairingPreflightOutboundCheck) 1331 } 1332 1333 // localPairingPreflightOutboundCheck creates a local tls server accessible via an outbound network address. 1334 // The function creates a client and makes an outbound network call to the local server. This function should be 1335 // triggered to ensure that the device has permissions to access its LAN or to make outbound network calls. 1336 // 1337 // In addition, the functionality attempts to address an issue with iOS devices https://stackoverflow.com/a/64242745 1338 func localPairingPreflightOutboundCheck() string { 1339 err := preflight.CheckOutbound() 1340 return makeJSONResponse(err) 1341 } 1342 1343 func StartSearchForLocalPairingPeers() string { 1344 return logAndCallString(startSearchForLocalPairingPeers) 1345 } 1346 1347 // startSearchForLocalPairingPeers starts a UDP multicast beacon that both listens for and broadcasts to LAN peers 1348 // on discovery the beacon will emit a signal with the details of the discovered peer. 1349 // 1350 // Currently, beacons are configured to search for 2 minutes pinging the network every 500 ms; 1351 // - If no peer discovery is made before this time elapses the operation will terminate. 1352 // - If a peer is discovered the pairing.PeerNotifier will terminate operation after 5 seconds, giving the peer 1353 // reasonable time to discover this device. 1354 // 1355 // Peer details are represented by a json.Marshal peers.LocalPairingPeerHello 1356 func startSearchForLocalPairingPeers() string { 1357 pn := pairing.NewPeerNotifier() 1358 err := pn.Search() 1359 return makeJSONResponse(err) 1360 } 1361 1362 func GetConnectionStringForBeingBootstrapped(configJSON string) string { 1363 return logAndCallString(getConnectionStringForBeingBootstrapped, configJSON) 1364 } 1365 1366 // getConnectionStringForBeingBootstrapped starts a pairing.ReceiverServer 1367 // then generates a pairing.ConnectionParams. Used when the device is Logged out or has no Account keys 1368 // and the device has no camera to read a QR code with 1369 // 1370 // Example: A desktop device (device without camera) receiving account data from mobile (device with camera) 1371 func getConnectionStringForBeingBootstrapped(configJSON string) string { 1372 if configJSON == "" { 1373 return makeJSONResponse(fmt.Errorf("no config given, PayloadSourceConfig is expected")) 1374 } 1375 1376 statusBackend.LocalPairingStateManager.SetPairing(true) 1377 defer func() { 1378 statusBackend.LocalPairingStateManager.SetPairing(false) 1379 }() 1380 1381 cs, err := pairing.StartUpReceiverServer(statusBackend, configJSON) 1382 if err != nil { 1383 return makeJSONResponse(err) 1384 } 1385 1386 err = statusBackend.Logout() 1387 if err != nil { 1388 return makeJSONResponse(err) 1389 } 1390 1391 return cs 1392 } 1393 1394 func GetConnectionStringForBootstrappingAnotherDevice(configJSON string) string { 1395 return logAndCallString(getConnectionStringForBootstrappingAnotherDevice, configJSON) 1396 } 1397 1398 // getConnectionStringForBootstrappingAnotherDevice starts a pairing.SenderServer 1399 // then generates a pairing.ConnectionParams. Used when the device is Logged in and therefore has Account keys 1400 // and the device might not have a camera 1401 // 1402 // Example: A mobile or desktop device (devices that MAY have a camera but MUST have a screen) 1403 // sending account data to a mobile (device with camera) 1404 func getConnectionStringForBootstrappingAnotherDevice(configJSON string) string { 1405 if configJSON == "" { 1406 return makeJSONResponse(fmt.Errorf("no config given, SendingServerConfig is expected")) 1407 } 1408 1409 statusBackend.LocalPairingStateManager.SetPairing(true) 1410 defer func() { 1411 statusBackend.LocalPairingStateManager.SetPairing(false) 1412 }() 1413 1414 cs, err := pairing.StartUpSenderServer(statusBackend, configJSON) 1415 if err != nil { 1416 return makeJSONResponse(err) 1417 } 1418 return cs 1419 } 1420 1421 type inputConnectionStringForBootstrappingResponse struct { 1422 InstallationID string `json:"installationId"` 1423 KeyUID string `json:"keyUID"` 1424 Error error `json:"error"` 1425 } 1426 1427 func (i *inputConnectionStringForBootstrappingResponse) toJSON(err error) string { 1428 i.Error = err 1429 j, _ := json.Marshal(i) 1430 return string(j) 1431 } 1432 1433 func InputConnectionStringForBootstrapping(cs, configJSON string) string { 1434 return logAndCallString(inputConnectionStringForBootstrapping, cs, configJSON) 1435 } 1436 1437 // inputConnectionStringForBootstrapping starts a pairing.ReceiverClient 1438 // The given server.ConnectionParams string will determine the server.Mode 1439 // 1440 // server.Mode = server.Sending 1441 // Used when the device is Logged out or has no Account keys and has a camera to read a QR code 1442 // 1443 // Example: A mobile device (device with a camera) receiving account data from 1444 // a device with a screen (mobile or desktop devices) 1445 func inputConnectionStringForBootstrapping(cs, configJSON string) string { 1446 var err error 1447 if configJSON == "" { 1448 return makeJSONResponse(fmt.Errorf("no config given, ReceiverClientConfig is expected")) 1449 } 1450 1451 params := &pairing.ConnectionParams{} 1452 err = params.FromString(cs) 1453 if err != nil { 1454 response := &inputConnectionStringForBootstrappingResponse{} 1455 return response.toJSON(fmt.Errorf("could not parse connection string")) 1456 } 1457 response := &inputConnectionStringForBootstrappingResponse{ 1458 InstallationID: params.InstallationID(), 1459 KeyUID: params.KeyUID(), 1460 } 1461 1462 err = statusBackend.LocalPairingStateManager.StartPairing(cs) 1463 defer func() { statusBackend.LocalPairingStateManager.StopPairing(cs, err) }() 1464 if err != nil { 1465 return response.toJSON(err) 1466 } 1467 1468 err = pairing.StartUpReceivingClient(statusBackend, cs, configJSON) 1469 if err != nil { 1470 return response.toJSON(err) 1471 } 1472 1473 return response.toJSON(statusBackend.Logout()) 1474 } 1475 1476 func InputConnectionStringForBootstrappingAnotherDevice(cs, configJSON string) string { 1477 return logAndCallString(inputConnectionStringForBootstrappingAnotherDevice, cs, configJSON) 1478 } 1479 1480 // inputConnectionStringForBootstrappingAnotherDevice starts a pairing.SendingClient 1481 // The given server.ConnectionParams string will determine the server.Mode 1482 // 1483 // server.Mode = server.Receiving 1484 // Used when the device is Logged in and therefore has Account keys and the has a camera to read a QR code 1485 // 1486 // Example: A mobile (device with camera) sending account data to a desktop device (device without camera) 1487 func inputConnectionStringForBootstrappingAnotherDevice(cs, configJSON string) string { 1488 var err error 1489 if configJSON == "" { 1490 return makeJSONResponse(fmt.Errorf("no config given, SenderClientConfig is expected")) 1491 } 1492 1493 err = statusBackend.LocalPairingStateManager.StartPairing(cs) 1494 defer func() { statusBackend.LocalPairingStateManager.StopPairing(cs, err) }() 1495 if err != nil { 1496 return makeJSONResponse(err) 1497 } 1498 1499 err = pairing.StartUpSendingClient(statusBackend, cs, configJSON) 1500 return makeJSONResponse(err) 1501 } 1502 1503 func GetConnectionStringForExportingKeypairsKeystores(configJSON string) string { 1504 return logAndCallString(getConnectionStringForExportingKeypairsKeystores, configJSON) 1505 } 1506 1507 // getConnectionStringForExportingKeypairsKeystores starts a pairing.SenderServer 1508 // then generates a pairing.ConnectionParams. Used when the device is Logged in and therefore has Account keys 1509 // and the device might not have a camera, to transfer kestore files of provided key uids. 1510 func getConnectionStringForExportingKeypairsKeystores(configJSON string) string { 1511 if configJSON == "" { 1512 return makeJSONResponse(fmt.Errorf("no config given, SendingServerConfig is expected")) 1513 } 1514 1515 cs, err := pairing.StartUpKeystoreFilesSenderServer(statusBackend, configJSON) 1516 if err != nil { 1517 return makeJSONResponse(err) 1518 } 1519 return cs 1520 } 1521 1522 func InputConnectionStringForImportingKeypairsKeystores(cs, configJSON string) string { 1523 return logAndCallString(inputConnectionStringForImportingKeypairsKeystores, cs, configJSON) 1524 } 1525 1526 // inputConnectionStringForImportingKeypairsKeystores starts a pairing.ReceiverClient 1527 // The given server.ConnectionParams string will determine the server.Mode 1528 // Used when the device is Logged in and has Account keys and has a camera to read a QR code 1529 // 1530 // Example: A mobile device (device with a camera) receiving account data from 1531 // a device with a screen (mobile or desktop devices) 1532 func inputConnectionStringForImportingKeypairsKeystores(cs, configJSON string) string { 1533 if configJSON == "" { 1534 return makeJSONResponse(fmt.Errorf("no config given, ReceiverClientConfig is expected")) 1535 } 1536 1537 err := pairing.StartUpKeystoreFilesReceivingClient(statusBackend, cs, configJSON) 1538 return makeJSONResponse(err) 1539 } 1540 1541 func ValidateConnectionString(cs string) string { 1542 return logAndCallString(validateConnectionString, cs) 1543 } 1544 1545 func validateConnectionString(cs string) string { 1546 err := pairing.ValidateConnectionString(cs) 1547 if err == nil { 1548 return "" 1549 } 1550 return err.Error() 1551 } 1552 1553 func EncodeTransfer(to string, value string) string { 1554 return logAndCallString(encodeTransfer, to, value) 1555 } 1556 1557 func encodeTransfer(to string, value string) string { 1558 result, err := abi_spec.EncodeTransfer(to, value) 1559 if err != nil { 1560 log.Error("failed to encode transfer", "to", to, "value", value, "error", err) 1561 return "" 1562 } 1563 return result 1564 } 1565 1566 func EncodeFunctionCall(method string, paramsJSON string) string { 1567 return logAndCallString(encodeFunctionCall, method, paramsJSON) 1568 } 1569 1570 func encodeFunctionCall(method string, paramsJSON string) string { 1571 result, err := abi_spec.Encode(method, paramsJSON) 1572 if err != nil { 1573 log.Error("failed to encode function call", "method", method, "paramsJSON", paramsJSON, "error", err) 1574 return "" 1575 } 1576 return result 1577 } 1578 1579 func DecodeParameters(decodeParamJSON string) string { 1580 return decodeParameters(decodeParamJSON) 1581 } 1582 1583 func decodeParameters(decodeParamJSON string) string { 1584 decodeParam := struct { 1585 BytesString string `json:"bytesString"` 1586 Types []string `json:"types"` 1587 }{} 1588 err := json.Unmarshal([]byte(decodeParamJSON), &decodeParam) 1589 if err != nil { 1590 log.Error("failed to unmarshal json when decoding parameters", "decodeParamJSON", decodeParamJSON, "error", err) 1591 return "" 1592 } 1593 result, err := abi_spec.Decode(decodeParam.BytesString, decodeParam.Types) 1594 if err != nil { 1595 log.Error("failed to decode parameters", "decodeParamJSON", decodeParamJSON, "error", err) 1596 return "" 1597 } 1598 bytes, err := json.Marshal(result) 1599 if err != nil { 1600 log.Error("failed to marshal result", "result", result, "decodeParamJSON", decodeParamJSON, "error", err) 1601 return "" 1602 } 1603 return string(bytes) 1604 } 1605 1606 func HexToNumber(hex string) string { 1607 return logAndCallString(hexToNumber, hex) 1608 } 1609 1610 func hexToNumber(hex string) string { 1611 return abi_spec.HexToNumber(hex) 1612 } 1613 1614 func NumberToHex(numString string) string { 1615 return logAndCallString(numberToHex, numString) 1616 } 1617 1618 func numberToHex(numString string) string { 1619 return abi_spec.NumberToHex(numString) 1620 } 1621 1622 func Sha3(str string) string { 1623 return "0x" + abi_spec.Sha3(str) 1624 } 1625 1626 func Utf8ToHex(str string) string { 1627 return logAndCallString(utf8ToHex, str) 1628 } 1629 1630 func utf8ToHex(str string) string { 1631 hexString, err := abi_spec.Utf8ToHex(str) 1632 if err != nil { 1633 log.Error("failed to convert utf8 to hex", "str", str, "error", err) 1634 } 1635 return hexString 1636 } 1637 1638 func HexToUtf8(hexString string) string { 1639 return logAndCallString(hexToUtf8, hexString) 1640 } 1641 1642 func hexToUtf8(hexString string) string { 1643 str, err := abi_spec.HexToUtf8(hexString) 1644 if err != nil { 1645 log.Error("failed to convert hex to utf8", "hexString", hexString, "error", err) 1646 } 1647 return str 1648 } 1649 1650 func CheckAddressChecksum(address string) string { 1651 return logAndCallString(checkAddressChecksum, address) 1652 } 1653 1654 func checkAddressChecksum(address string) string { 1655 valid, err := abi_spec.CheckAddressChecksum(address) 1656 if err != nil { 1657 log.Error("failed to invoke check address checksum", "address", address, "error", err) 1658 } 1659 result, _ := json.Marshal(valid) 1660 return string(result) 1661 } 1662 1663 func IsAddress(address string) string { 1664 return logAndCallString(isAddress, address) 1665 } 1666 1667 func isAddress(address string) string { 1668 valid, err := abi_spec.IsAddress(address) 1669 if err != nil { 1670 log.Error("failed to invoke IsAddress", "address", address, "error", err) 1671 } 1672 result, _ := json.Marshal(valid) 1673 return string(result) 1674 } 1675 1676 func ToChecksumAddress(address string) string { 1677 return logAndCallString(toChecksumAddress, address) 1678 } 1679 1680 func toChecksumAddress(address string) string { 1681 address, err := abi_spec.ToChecksumAddress(address) 1682 if err != nil { 1683 log.Error("failed to convert to checksum address", "address", address, "error", err) 1684 } 1685 return address 1686 } 1687 1688 func DeserializeAndCompressKey(DesktopKey string) string { 1689 return logAndCallString(deserializeAndCompressKey, DesktopKey) 1690 } 1691 1692 func deserializeAndCompressKey(DesktopKey string) string { 1693 deserialisedKey := MultiformatDeserializePublicKey(DesktopKey, "f") 1694 sanitisedKey := "0x" + deserialisedKey[5:] 1695 return CompressPublicKey(sanitisedKey) 1696 } 1697 1698 type InitLoggingRequest struct { 1699 logutils.LogSettings 1700 LogRequestGo bool `json:"LogRequestGo"` 1701 LogRequestFile string `json:"LogRequestFile"` 1702 } 1703 1704 // InitLogging The InitLogging function should be called when the application starts. 1705 // This ensures that we can capture logs before the user login. Subsequent calls will update the logger settings. 1706 // Before this, we can only capture logs after user login since we will only configure the logging after the login process. 1707 func InitLogging(logSettingsJSON string) string { 1708 var logSettings InitLoggingRequest 1709 var err error 1710 if err = json.Unmarshal([]byte(logSettingsJSON), &logSettings); err != nil { 1711 return makeJSONResponse(err) 1712 } 1713 1714 if err = logutils.OverrideRootLogWithConfig(logSettings.LogSettings, false); err == nil { 1715 log.Info("logging initialised", "logSettings", logSettingsJSON) 1716 } 1717 1718 if logSettings.LogRequestGo { 1719 err = requestlog.ConfigureAndEnableRequestLogging(logSettings.LogRequestFile) 1720 if err != nil { 1721 return makeJSONResponse(err) 1722 } 1723 } 1724 1725 return makeJSONResponse(err) 1726 } 1727 1728 func GetRandomMnemonic() string { 1729 mnemonic, err := account.GetRandomMnemonic() 1730 if err != nil { 1731 return makeJSONResponse(err) 1732 } 1733 return mnemonic 1734 } 1735 1736 func ToggleCentralizedMetrics(requestJSON string) string { 1737 return logAndCallString(toggleCentralizedMetrics, requestJSON) 1738 } 1739 1740 func toggleCentralizedMetrics(requestJSON string) string { 1741 var request requests.ToggleCentralizedMetrics 1742 err := json.Unmarshal([]byte(requestJSON), &request) 1743 if err != nil { 1744 return makeJSONResponse(err) 1745 } 1746 1747 err = request.Validate() 1748 if err != nil { 1749 return makeJSONResponse(err) 1750 } 1751 1752 err = statusBackend.ToggleCentralizedMetrics(request.Enabled) 1753 if err != nil { 1754 return makeJSONResponse(err) 1755 } 1756 1757 return makeJSONResponse(nil) 1758 } 1759 1760 func CentralizedMetricsInfo() string { 1761 return logAndCallString(centralizedMetricsInfo) 1762 } 1763 1764 func centralizedMetricsInfo() string { 1765 metricsInfo, err := statusBackend.CentralizedMetricsInfo() 1766 if err != nil { 1767 return makeJSONResponse(err) 1768 } 1769 data, err := json.Marshal(metricsInfo) 1770 if err != nil { 1771 return makeJSONResponse(err) 1772 } 1773 return string(data) 1774 } 1775 1776 func AddCentralizedMetric(requestJSON string) string { 1777 return logAndCallString(addCentralizedMetric, requestJSON) 1778 } 1779 1780 func addCentralizedMetric(requestJSON string) string { 1781 var request requests.AddCentralizedMetric 1782 err := json.Unmarshal([]byte(requestJSON), &request) 1783 if err != nil { 1784 return makeJSONResponse(err) 1785 } 1786 1787 err = request.Validate() 1788 if err != nil { 1789 return makeJSONResponse(err) 1790 } 1791 metric := request.Metric 1792 1793 metric.EnsureID() 1794 err = statusBackend.AddCentralizedMetric(*metric) 1795 if err != nil { 1796 return makeJSONResponse(err) 1797 } 1798 1799 return metric.ID 1800 }