2019-02-01 17:02:52 +00:00
|
|
|
package statusgo
|
|
|
|
|
|
|
|
import (
|
2019-02-15 11:31:20 +00:00
|
|
|
"encoding/hex"
|
2019-02-01 17:02:52 +00:00
|
|
|
"encoding/json"
|
2019-03-04 14:33:48 +00:00
|
|
|
"errors"
|
2019-02-01 17:02:52 +00:00
|
|
|
"fmt"
|
|
|
|
"unsafe"
|
|
|
|
|
2020-01-02 09:10:19 +00:00
|
|
|
validator "gopkg.in/go-playground/validator.v9"
|
|
|
|
|
2019-02-01 17:02:52 +00:00
|
|
|
"github.com/ethereum/go-ethereum/log"
|
2022-10-25 14:25:08 +00:00
|
|
|
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
2020-01-02 09:10:19 +00:00
|
|
|
|
2022-03-18 12:20:13 +00:00
|
|
|
"github.com/status-im/zxcvbn-go"
|
2022-03-23 14:19:19 +00:00
|
|
|
"github.com/status-im/zxcvbn-go/scoring"
|
2022-03-18 12:20:13 +00:00
|
|
|
|
2022-08-24 12:42:41 +00:00
|
|
|
abi_spec "github.com/status-im/status-go/abi-spec"
|
2024-02-19 12:53:01 +00:00
|
|
|
"github.com/status-im/status-go/account"
|
2019-02-01 17:02:52 +00:00
|
|
|
"github.com/status-im/status-go/api"
|
2020-06-23 10:47:17 +00:00
|
|
|
"github.com/status-im/status-go/api/multiformat"
|
2024-07-03 11:51:14 +00:00
|
|
|
"github.com/status-im/status-go/centralizedmetrics"
|
|
|
|
"github.com/status-im/status-go/centralizedmetrics/providers"
|
2022-10-25 09:32:26 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
2019-11-23 17:57:05 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
2019-03-04 14:33:48 +00:00
|
|
|
"github.com/status-im/status-go/exportlogs"
|
2022-08-07 07:35:54 +00:00
|
|
|
"github.com/status-im/status-go/extkeys"
|
2022-04-06 11:08:52 +00:00
|
|
|
"github.com/status-im/status-go/images"
|
2023-07-12 22:29:38 +00:00
|
|
|
"github.com/status-im/status-go/logutils"
|
2024-09-13 15:08:20 +00:00
|
|
|
"github.com/status-im/status-go/logutils/requestlog"
|
2019-08-20 15:38:40 +00:00
|
|
|
"github.com/status-im/status-go/multiaccounts"
|
|
|
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
2022-03-23 18:47:00 +00:00
|
|
|
"github.com/status-im/status-go/multiaccounts/settings"
|
2019-02-01 17:02:52 +00:00
|
|
|
"github.com/status-im/status-go/params"
|
|
|
|
"github.com/status-im/status-go/profiling"
|
2023-03-16 14:49:25 +00:00
|
|
|
"github.com/status-im/status-go/protocol"
|
2022-10-25 09:32:26 +00:00
|
|
|
"github.com/status-im/status-go/protocol/common"
|
2022-04-08 17:54:29 +00:00
|
|
|
identityUtils "github.com/status-im/status-go/protocol/identity"
|
2022-02-17 15:13:10 +00:00
|
|
|
"github.com/status-im/status-go/protocol/identity/alias"
|
2022-03-17 16:58:35 +00:00
|
|
|
"github.com/status-im/status-go/protocol/identity/colorhash"
|
|
|
|
"github.com/status-im/status-go/protocol/identity/emojihash"
|
2023-03-16 14:49:25 +00:00
|
|
|
"github.com/status-im/status-go/protocol/requests"
|
2022-02-23 14:34:16 +00:00
|
|
|
"github.com/status-im/status-go/server"
|
2023-01-06 12:21:14 +00:00
|
|
|
"github.com/status-im/status-go/server/pairing"
|
2023-06-02 03:05:51 +00:00
|
|
|
"github.com/status-im/status-go/server/pairing/preflight"
|
2019-02-01 17:02:52 +00:00
|
|
|
"github.com/status-im/status-go/services/personal"
|
2019-03-04 13:45:27 +00:00
|
|
|
"github.com/status-im/status-go/services/typeddata"
|
2019-02-01 17:02:52 +00:00
|
|
|
"github.com/status-im/status-go/signal"
|
|
|
|
"github.com/status-im/status-go/transactions"
|
|
|
|
)
|
|
|
|
|
2024-07-03 11:51:14 +00:00
|
|
|
type InitializeApplicationResponse struct {
|
|
|
|
Accounts []multiaccounts.Account `json:"accounts"`
|
|
|
|
CentralizedMetricsInfo *centralizedmetrics.MetricsInfo `json:"centralizedMetricsInfo"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func InitializeApplication(requestJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(initializeApplication, requestJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
func initializeApplication(requestJSON string) string {
|
2024-07-03 11:51:14 +00:00
|
|
|
var request requests.InitializeApplication
|
|
|
|
err := json.Unmarshal([]byte(requestJSON), &request)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
err = request.Validate()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialize metrics
|
|
|
|
providers.MixpanelAppID = request.MixpanelAppID
|
|
|
|
providers.MixpanelToken = request.MixpanelToken
|
|
|
|
|
|
|
|
datadir := request.DataDir
|
|
|
|
|
|
|
|
statusBackend.UpdateRootDataDir(datadir)
|
|
|
|
err = statusBackend.OpenAccounts()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
accs, err := statusBackend.GetAccounts()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
centralizedMetricsInfo, err := statusBackend.CentralizedMetricsInfo()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
response := &InitializeApplicationResponse{
|
|
|
|
Accounts: accs,
|
|
|
|
CentralizedMetricsInfo: centralizedMetricsInfo,
|
|
|
|
}
|
|
|
|
data, err := json.Marshal(response)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return string(data)
|
|
|
|
}
|
|
|
|
|
2019-08-20 15:38:40 +00:00
|
|
|
func OpenAccounts(datadir string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(openAccounts, datadir)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DEPRECATED: use InitializeApplication
|
|
|
|
// openAccounts opens database and returns accounts list.
|
|
|
|
func openAccounts(datadir string) string {
|
2019-08-20 15:38:40 +00:00
|
|
|
statusBackend.UpdateRootDataDir(datadir)
|
|
|
|
err := statusBackend.OpenAccounts()
|
2019-02-01 17:02:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2019-08-20 15:38:40 +00:00
|
|
|
accs, err := statusBackend.GetAccounts()
|
2019-02-01 17:02:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2019-08-20 15:38:40 +00:00
|
|
|
data, err := json.Marshal(accs)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return string(data)
|
2019-02-01 17:02:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func ExtractGroupMembershipSignatures(signaturePairsStr string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(extractGroupMembershipSignatures, signaturePairsStr)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExtractGroupMembershipSignatures extract public keys from tuples of content/signature.
|
|
|
|
func extractGroupMembershipSignatures(signaturePairsStr string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
var signaturePairs [][2]string
|
|
|
|
|
|
|
|
if err := json.Unmarshal([]byte(signaturePairsStr), &signaturePairs); err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
identities, err := statusBackend.ExtractGroupMembershipSignatures(signaturePairs)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := json.Marshal(struct {
|
|
|
|
Identities []string `json:"identities"`
|
|
|
|
}{Identities: identities})
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func SignGroupMembership(content string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(signGroupMembership, content)
|
|
|
|
}
|
|
|
|
|
|
|
|
// signGroupMembership signs a string containing group membership information.
|
|
|
|
func signGroupMembership(content string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
signature, err := statusBackend.SignGroupMembership(content)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := json.Marshal(struct {
|
|
|
|
Signature string `json:"signature"`
|
|
|
|
}{Signature: signature})
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(data)
|
|
|
|
}
|
|
|
|
|
2021-04-29 19:22:10 +00:00
|
|
|
func GetNodeConfig() string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(getNodeConfig)
|
|
|
|
}
|
|
|
|
|
|
|
|
// getNodeConfig returns the current config of the Status node
|
|
|
|
func getNodeConfig() string {
|
2021-04-29 19:22:10 +00:00
|
|
|
conf, err := statusBackend.GetNodeConfig()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
respJSON, err := json.Marshal(conf)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(respJSON)
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:02:52 +00:00
|
|
|
func ValidateNodeConfig(configJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(validateNodeConfig, configJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
// validateNodeConfig validates config for the Status node.
|
|
|
|
func validateNodeConfig(configJSON string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
var resp APIDetailedResponse
|
|
|
|
|
|
|
|
_, err := params.NewConfigFromJSON(configJSON)
|
|
|
|
|
|
|
|
// Convert errors to APIDetailedResponse
|
|
|
|
switch err := err.(type) {
|
|
|
|
case validator.ValidationErrors:
|
|
|
|
resp = APIDetailedResponse{
|
|
|
|
Message: "validation: validation failed",
|
|
|
|
FieldErrors: make([]APIFieldError, len(err)),
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, ve := range err {
|
|
|
|
resp.FieldErrors[i] = APIFieldError{
|
|
|
|
Parameter: ve.Namespace(),
|
|
|
|
Errors: []APIError{
|
|
|
|
{
|
|
|
|
Message: fmt.Sprintf("field validation failed on the '%s' tag", ve.Tag()),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case error:
|
|
|
|
resp = APIDetailedResponse{
|
|
|
|
Message: fmt.Sprintf("validation: %s", err.Error()),
|
|
|
|
}
|
|
|
|
case nil:
|
|
|
|
resp = APIDetailedResponse{
|
|
|
|
Status: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
respJSON, err := json.Marshal(resp)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(respJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
func ResetChainData() string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(resetChainData)
|
|
|
|
}
|
|
|
|
|
|
|
|
// resetChainData removes chain data from data directory.
|
|
|
|
func resetChainData() string {
|
2019-02-01 17:02:52 +00:00
|
|
|
api.RunAsync(statusBackend.ResetChainData)
|
|
|
|
return makeJSONResponse(nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func CallRPC(inputJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(callRPC, inputJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
// callRPC calls public APIs via RPC.
|
|
|
|
func callRPC(inputJSON string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
resp, err := statusBackend.CallRPC(inputJSON)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return resp
|
|
|
|
}
|
|
|
|
|
|
|
|
func CallPrivateRPC(inputJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(callPrivateRPC, inputJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
// callPrivateRPC calls both public and private APIs via RPC.
|
|
|
|
func callPrivateRPC(inputJSON string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
resp, err := statusBackend.CallPrivateRPC(inputJSON)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return resp
|
|
|
|
}
|
|
|
|
|
|
|
|
func VerifyAccountPassword(keyStoreDir, address, password string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(verifyAccountPassword, keyStoreDir, address, password)
|
|
|
|
}
|
|
|
|
|
|
|
|
// verifyAccountPassword verifies account password.
|
|
|
|
func verifyAccountPassword(keyStoreDir, address, password string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
_, err := statusBackend.AccountManager().VerifyAccountPassword(keyStoreDir, address, password)
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2021-07-20 11:48:10 +00:00
|
|
|
func VerifyDatabasePassword(keyUID, password string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(verifyDatabasePassword, keyUID, password)
|
|
|
|
}
|
|
|
|
|
|
|
|
// verifyDatabasePassword verifies database password.
|
|
|
|
func verifyDatabasePassword(keyUID, password string) string {
|
|
|
|
err := statusBackend.VerifyDatabasePassword(keyUID, password)
|
|
|
|
return makeJSONResponse(err)
|
2021-07-20 11:48:10 +00:00
|
|
|
}
|
|
|
|
|
2020-06-22 12:03:28 +00:00
|
|
|
func MigrateKeyStoreDir(accountData, password, oldDir, newDir string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(migrateKeyStoreDir, accountData, password, oldDir, newDir)
|
|
|
|
}
|
|
|
|
|
|
|
|
// migrateKeyStoreDir migrates key files to a new directory
|
|
|
|
func migrateKeyStoreDir(accountData, password, oldDir, newDir string) string {
|
2020-06-22 12:03:28 +00:00
|
|
|
var account multiaccounts.Account
|
|
|
|
err := json.Unmarshal([]byte(accountData), &account)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = statusBackend.MigrateKeyStoreDir(account, password, oldDir, newDir)
|
2024-09-13 15:08:20 +00:00
|
|
|
return makeJSONResponse(err)
|
2020-06-22 12:03:28 +00:00
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
// login deprecated as Login and LoginWithConfig are deprecated
|
2021-12-21 14:27:18 +00:00
|
|
|
func login(accountData, password, configJSON string) error {
|
2019-08-20 15:38:40 +00:00
|
|
|
var account multiaccounts.Account
|
|
|
|
err := json.Unmarshal([]byte(accountData), &account)
|
2019-07-26 14:45:10 +00:00
|
|
|
if err != nil {
|
2021-12-21 14:27:18 +00:00
|
|
|
return err
|
2019-07-26 14:45:10 +00:00
|
|
|
}
|
2021-12-21 14:27:18 +00:00
|
|
|
|
|
|
|
var conf params.NodeConfig
|
|
|
|
if configJSON != "" {
|
|
|
|
err = json.Unmarshal([]byte(configJSON), &conf)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-20 15:38:40 +00:00
|
|
|
api.RunAsync(func() error {
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Debug("start a node with account", "key-uid", account.KeyUID)
|
2024-02-27 19:00:20 +00:00
|
|
|
err := statusBackend.UpdateNodeConfigFleet(account, password, &conf)
|
2024-02-27 16:15:11 +00:00
|
|
|
if err != nil {
|
2024-02-28 15:42:32 +00:00
|
|
|
log.Error("failed to update node config fleet", "key-uid", account.KeyUID, "error", err)
|
|
|
|
return statusBackend.LoggedIn(account.KeyUID, err)
|
2024-02-27 16:15:11 +00:00
|
|
|
}
|
|
|
|
|
2024-06-26 11:14:27 +00:00
|
|
|
err = statusBackend.StartNodeWithAccount(account, password, &conf, nil)
|
2019-08-20 15:38:40 +00:00
|
|
|
if err != nil {
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Error("failed to start a node", "key-uid", account.KeyUID, "error", err)
|
2019-08-20 15:38:40 +00:00
|
|
|
return err
|
|
|
|
}
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Debug("started a node with", "key-uid", account.KeyUID)
|
2019-08-20 15:38:40 +00:00
|
|
|
return nil
|
|
|
|
})
|
2021-12-21 14:27:18 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Login loads a key file (for a given address), tries to decrypt it using the password,
|
|
|
|
// to verify ownership if verified, purges all the previous identities from Whisper,
|
|
|
|
// and injects verified key as shh identity.
|
2024-09-13 15:08:20 +00:00
|
|
|
//
|
|
|
|
// Deprecated: Use LoginAccount instead.
|
2021-12-21 14:27:18 +00:00
|
|
|
func Login(accountData, password string) string {
|
|
|
|
err := login(accountData, password, "")
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return makeJSONResponse(nil)
|
|
|
|
}
|
|
|
|
|
2024-03-28 15:01:44 +00:00
|
|
|
// LoginWithConfig loads a key file (for a given address), tries to decrypt it using the password,
|
2021-12-21 14:27:18 +00:00
|
|
|
// to verify ownership if verified, purges all the previous identities from Whisper,
|
2022-02-27 14:46:17 +00:00
|
|
|
// and injects verified key as shh identity. It then updates the accounts node db configuration
|
2021-12-21 14:27:18 +00:00
|
|
|
// mergin the values received in the configJSON parameter
|
2024-03-28 15:01:44 +00:00
|
|
|
//
|
|
|
|
// Deprecated: Use LoginAccount instead.
|
2021-12-21 14:27:18 +00:00
|
|
|
func LoginWithConfig(accountData, password, configJSON string) string {
|
|
|
|
err := login(accountData, password, configJSON)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2019-08-20 15:38:40 +00:00
|
|
|
return makeJSONResponse(nil)
|
|
|
|
}
|
2019-07-26 14:45:10 +00:00
|
|
|
|
2023-03-16 14:49:25 +00:00
|
|
|
func CreateAccountAndLogin(requestJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(createAccountAndLogin, requestJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
func createAccountAndLogin(requestJSON string) string {
|
2023-03-16 14:49:25 +00:00
|
|
|
var request requests.CreateAccount
|
|
|
|
err := json.Unmarshal([]byte(requestJSON), &request)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2024-03-28 15:01:44 +00:00
|
|
|
err = request.Validate(&requests.CreateAccountValidation{
|
|
|
|
AllowEmptyDisplayName: false,
|
|
|
|
})
|
2023-03-16 14:49:25 +00:00
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
api.RunAsync(func() error {
|
|
|
|
log.Debug("starting a node and creating config")
|
2023-10-10 16:12:38 +00:00
|
|
|
_, err := statusBackend.CreateAccountAndLogin(&request)
|
2023-03-16 14:49:25 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to create account", "error", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
log.Debug("started a node, and created account")
|
|
|
|
return nil
|
2023-03-21 17:02:04 +00:00
|
|
|
})
|
|
|
|
return makeJSONResponse(nil)
|
|
|
|
}
|
|
|
|
|
2023-05-24 15:02:53 +00:00
|
|
|
func LoginAccount(requestJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(loginAccount, requestJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
func loginAccount(requestJSON string) string {
|
2023-05-24 15:02:53 +00:00
|
|
|
var request requests.Login
|
|
|
|
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 {
|
|
|
|
err := statusBackend.LoginAccount(&request)
|
|
|
|
if err != nil {
|
2023-12-12 03:15:26 +00:00
|
|
|
log.Error("loginAccount failed", "error", err)
|
2023-05-24 15:02:53 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
log.Debug("loginAccount started node")
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return makeJSONResponse(nil)
|
|
|
|
}
|
|
|
|
|
2023-03-21 17:02:04 +00:00
|
|
|
func RestoreAccountAndLogin(requestJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(restoreAccountAndLogin, requestJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
func restoreAccountAndLogin(requestJSON string) string {
|
2023-03-21 17:02:04 +00:00
|
|
|
var request requests.RestoreAccount
|
|
|
|
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 restoring account")
|
2024-06-26 11:14:27 +00:00
|
|
|
|
|
|
|
if request.Keycard != nil {
|
|
|
|
_, err = statusBackend.RestoreKeycardAccountAndLogin(&request)
|
|
|
|
} else {
|
|
|
|
_, err = statusBackend.RestoreAccountAndLogin(&request)
|
|
|
|
}
|
|
|
|
|
2023-03-21 17:02:04 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to restore account", "error", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
log.Debug("started a node, and restored account")
|
|
|
|
return nil
|
2023-03-16 14:49:25 +00:00
|
|
|
})
|
2024-06-26 11:14:27 +00:00
|
|
|
|
2023-03-16 14:49:25 +00:00
|
|
|
return makeJSONResponse(nil)
|
|
|
|
}
|
|
|
|
|
2024-03-28 15:01:44 +00:00
|
|
|
// SaveAccountAndLogin saves account in status-go database.
|
|
|
|
// Deprecated: Use CreateAccountAndLogin instead.
|
2019-12-27 09:58:25 +00:00
|
|
|
func SaveAccountAndLogin(accountData, password, settingsJSON, configJSON, subaccountData string) string {
|
2019-08-20 15:38:40 +00:00
|
|
|
var account multiaccounts.Account
|
|
|
|
err := json.Unmarshal([]byte(accountData), &account)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2022-03-23 18:47:00 +00:00
|
|
|
var settings settings.Settings
|
2019-12-27 09:58:25 +00:00
|
|
|
err = json.Unmarshal([]byte(settingsJSON), &settings)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2023-10-31 12:42:33 +00:00
|
|
|
|
2023-10-31 12:50:26 +00:00
|
|
|
if *settings.Mnemonic != "" {
|
2023-12-01 11:30:42 +00:00
|
|
|
settings.MnemonicWasNotShown = true
|
2023-10-31 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
2019-08-20 15:38:40 +00:00
|
|
|
var conf params.NodeConfig
|
|
|
|
err = json.Unmarshal([]byte(configJSON), &conf)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2022-05-18 10:42:51 +00:00
|
|
|
var subaccs []*accounts.Account
|
2019-08-20 15:38:40 +00:00
|
|
|
err = json.Unmarshal([]byte(subaccountData), &subaccs)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2022-04-08 17:54:29 +00:00
|
|
|
|
2019-08-20 15:38:40 +00:00
|
|
|
api.RunAsync(func() error {
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Debug("starting a node, and saving account with configuration", "key-uid", account.KeyUID)
|
2024-06-26 11:14:27 +00:00
|
|
|
err := statusBackend.StartNodeWithAccountAndInitialConfig(account, password, settings, &conf, subaccs, nil)
|
2019-08-20 15:38:40 +00:00
|
|
|
if err != nil {
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Error("failed to start node and save account", "key-uid", account.KeyUID, "error", err)
|
2019-08-20 15:38:40 +00:00
|
|
|
return err
|
|
|
|
}
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Debug("started a node, and saved account", "key-uid", account.KeyUID)
|
2019-08-20 15:38:40 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return makeJSONResponse(nil)
|
|
|
|
}
|
|
|
|
|
2020-07-13 10:45:36 +00:00
|
|
|
func DeleteMultiaccount(keyUID, keyStoreDir string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(deleteMultiaccount, keyUID, keyStoreDir)
|
|
|
|
}
|
2020-07-13 10:45:36 +00:00
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
// deleteMultiaccount
|
|
|
|
func deleteMultiaccount(keyUID, keyStoreDir string) string {
|
|
|
|
err := statusBackend.DeleteMultiaccount(keyUID, keyStoreDir)
|
|
|
|
return makeJSONResponse(err)
|
2020-07-13 10:45:36 +00:00
|
|
|
}
|
|
|
|
|
2021-08-13 07:24:33 +00:00
|
|
|
func DeleteImportedKey(address, password, keyStoreDir string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(deleteImportedKey, address, password, keyStoreDir)
|
|
|
|
}
|
2021-08-13 07:24:33 +00:00
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
// deleteImportedKey
|
|
|
|
func deleteImportedKey(address, password, keyStoreDir string) string {
|
|
|
|
err := statusBackend.DeleteImportedKey(address, password, keyStoreDir)
|
|
|
|
return makeJSONResponse(err)
|
2021-08-13 07:24:33 +00:00
|
|
|
}
|
|
|
|
|
2019-08-20 15:38:40 +00:00
|
|
|
func InitKeystore(keydir string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(initKeystore, keydir)
|
|
|
|
}
|
|
|
|
|
|
|
|
// initKeystore initialize keystore before doing any operations with keys.
|
|
|
|
func initKeystore(keydir string) string {
|
2019-08-20 15:38:40 +00:00
|
|
|
err := statusBackend.AccountManager().InitKeystore(keydir)
|
2019-02-01 17:02:52 +00:00
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2024-06-26 11:14:27 +00:00
|
|
|
// SaveAccountAndLoginWithKeycard saves account in status-go database.
|
|
|
|
// Deprecated: Use CreateAndAccountAndLogin with required keycard properties.
|
2019-12-27 09:58:25 +00:00
|
|
|
func SaveAccountAndLoginWithKeycard(accountData, password, settingsJSON, configJSON, subaccountData string, keyHex string) string {
|
2019-09-02 19:03:15 +00:00
|
|
|
var account multiaccounts.Account
|
|
|
|
err := json.Unmarshal([]byte(accountData), &account)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2022-03-23 18:47:00 +00:00
|
|
|
var settings settings.Settings
|
2019-12-27 09:58:25 +00:00
|
|
|
err = json.Unmarshal([]byte(settingsJSON), &settings)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2019-09-02 19:03:15 +00:00
|
|
|
var conf params.NodeConfig
|
|
|
|
err = json.Unmarshal([]byte(configJSON), &conf)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2022-05-18 10:42:51 +00:00
|
|
|
var subaccs []*accounts.Account
|
2019-12-18 15:09:04 +00:00
|
|
|
err = json.Unmarshal([]byte(subaccountData), &subaccs)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2022-10-19 15:19:30 +00:00
|
|
|
|
2019-09-02 19:03:15 +00:00
|
|
|
api.RunAsync(func() error {
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Debug("starting a node, and saving account with configuration", "key-uid", account.KeyUID)
|
2019-12-27 09:58:25 +00:00
|
|
|
err := statusBackend.SaveAccountAndStartNodeWithKey(account, password, settings, &conf, subaccs, keyHex)
|
2019-09-02 19:03:15 +00:00
|
|
|
if err != nil {
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Error("failed to start node and save account", "key-uid", account.KeyUID, "error", err)
|
2019-09-02 19:03:15 +00:00
|
|
|
return err
|
|
|
|
}
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Debug("started a node, and saved account", "key-uid", account.KeyUID)
|
2019-09-02 19:03:15 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return makeJSONResponse(nil)
|
|
|
|
}
|
|
|
|
|
2019-02-11 20:20:59 +00:00
|
|
|
// LoginWithKeycard initializes an account with a chat key and encryption key used for PFS.
|
|
|
|
// It purges all the previous identities from Whisper, and injects the key as shh identity.
|
2024-06-26 11:14:27 +00:00
|
|
|
// Deprecated: Use LoginAccount instead.
|
2023-07-20 10:08:57 +00:00
|
|
|
func LoginWithKeycard(accountData, password, keyHex string, configJSON string) string {
|
2019-09-02 19:03:15 +00:00
|
|
|
var account multiaccounts.Account
|
|
|
|
err := json.Unmarshal([]byte(accountData), &account)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2023-07-20 10:08:57 +00:00
|
|
|
var conf params.NodeConfig
|
|
|
|
err = json.Unmarshal([]byte(configJSON), &conf)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2019-09-02 19:03:15 +00:00
|
|
|
api.RunAsync(func() error {
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Debug("start a node with account", "key-uid", account.KeyUID)
|
2023-07-20 10:08:57 +00:00
|
|
|
err := statusBackend.StartNodeWithKey(account, password, keyHex, &conf)
|
2019-09-02 19:03:15 +00:00
|
|
|
if err != nil {
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Error("failed to start a node", "key-uid", account.KeyUID, "error", err)
|
2019-09-02 19:03:15 +00:00
|
|
|
return err
|
|
|
|
}
|
2019-12-05 08:00:57 +00:00
|
|
|
log.Debug("started a node with", "key-uid", account.KeyUID)
|
2019-09-02 19:03:15 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return makeJSONResponse(nil)
|
2019-02-11 20:20:59 +00:00
|
|
|
}
|
|
|
|
|
2019-02-01 17:02:52 +00:00
|
|
|
func Logout() string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(logout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// logout is equivalent to clearing whisper identities.
|
|
|
|
func logout() string {
|
|
|
|
return makeJSONResponse(statusBackend.Logout())
|
2019-02-01 17:02:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func SignMessage(rpcParams string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(signMessage, rpcParams)
|
|
|
|
}
|
|
|
|
|
|
|
|
// signMessage unmarshals rpc params {data, address, password} and
|
|
|
|
// passes them onto backend.SignMessage.
|
|
|
|
func signMessage(rpcParams string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
var params personal.SignParams
|
|
|
|
err := json.Unmarshal([]byte(rpcParams), ¶ms)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
result, err := statusBackend.SignMessage(params)
|
|
|
|
return prepareJSONResponse(result.String(), err)
|
|
|
|
}
|
|
|
|
|
2019-03-04 13:45:27 +00:00
|
|
|
// SignTypedData unmarshall data into TypedData, validate it and signs with selected account,
|
|
|
|
// if password matches selected account.
|
2022-12-29 06:16:19 +00:00
|
|
|
//
|
2019-03-04 13:45:27 +00:00
|
|
|
//export SignTypedData
|
2019-07-26 14:45:10 +00:00
|
|
|
func SignTypedData(data, address, password string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(signTypedData, data, address, password)
|
|
|
|
}
|
|
|
|
|
|
|
|
func signTypedData(data, address, password string) string {
|
2019-03-04 13:45:27 +00:00
|
|
|
var typed typeddata.TypedData
|
|
|
|
err := json.Unmarshal([]byte(data), &typed)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
if err := typed.Validate(); err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
2019-07-26 14:45:10 +00:00
|
|
|
result, err := statusBackend.SignTypedData(typed, address, password)
|
2019-03-04 13:45:27 +00:00
|
|
|
return prepareJSONResponse(result.String(), err)
|
|
|
|
}
|
|
|
|
|
2019-03-28 14:56:21 +00:00
|
|
|
// HashTypedData unmarshalls data into TypedData, validates it and hashes it.
|
2022-12-29 06:16:19 +00:00
|
|
|
//
|
2022-03-18 12:20:13 +00:00
|
|
|
//export HashTypedData
|
2019-03-28 14:56:21 +00:00
|
|
|
func HashTypedData(data string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(hashTypedData, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func hashTypedData(data string) string {
|
2019-03-28 14:56:21 +00:00
|
|
|
var typed typeddata.TypedData
|
|
|
|
err := json.Unmarshal([]byte(data), &typed)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
if err := typed.Validate(); err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
result, err := statusBackend.HashTypedData(typed)
|
|
|
|
return prepareJSONResponse(result.String(), err)
|
|
|
|
}
|
|
|
|
|
2020-10-29 07:46:02 +00:00
|
|
|
// SignTypedDataV4 unmarshall data into TypedData, validate it and signs with selected account,
|
|
|
|
// if password matches selected account.
|
2022-12-29 06:16:19 +00:00
|
|
|
//
|
2020-10-29 07:46:02 +00:00
|
|
|
//export SignTypedDataV4
|
|
|
|
func SignTypedDataV4(data, address, password string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(signTypedDataV4, data, address, password)
|
|
|
|
}
|
|
|
|
|
|
|
|
func signTypedDataV4(data, address, password string) string {
|
2022-10-25 14:25:08 +00:00
|
|
|
var typed apitypes.TypedData
|
2020-10-29 07:46:02 +00:00
|
|
|
err := json.Unmarshal([]byte(data), &typed)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
result, err := statusBackend.SignTypedDataV4(typed, address, password)
|
|
|
|
return prepareJSONResponse(result.String(), err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// HashTypedDataV4 unmarshalls data into TypedData, validates it and hashes it.
|
2022-12-29 06:16:19 +00:00
|
|
|
//
|
2022-03-18 12:20:13 +00:00
|
|
|
//export HashTypedDataV4
|
2020-10-29 07:46:02 +00:00
|
|
|
func HashTypedDataV4(data string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(hashTypedDataV4, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func hashTypedDataV4(data string) string {
|
2022-10-25 14:25:08 +00:00
|
|
|
var typed apitypes.TypedData
|
2020-10-29 07:46:02 +00:00
|
|
|
err := json.Unmarshal([]byte(data), &typed)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
result, err := statusBackend.HashTypedDataV4(typed)
|
|
|
|
return prepareJSONResponse(result.String(), err)
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:02:52 +00:00
|
|
|
func Recover(rpcParams string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(recoverWithRPCParams, rpcParams)
|
|
|
|
}
|
|
|
|
|
|
|
|
// recoverWithRPCParams unmarshals rpc params {signDataString, signedData} and passes
|
|
|
|
// them onto backend.
|
|
|
|
func recoverWithRPCParams(rpcParams string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
var params personal.RecoverParams
|
|
|
|
err := json.Unmarshal([]byte(rpcParams), ¶ms)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
addr, err := statusBackend.Recover(params)
|
|
|
|
return prepareJSONResponse(addr.String(), err)
|
|
|
|
}
|
|
|
|
|
2022-06-09 13:09:56 +00:00
|
|
|
func SendTransactionWithChainID(chainID int, txArgsJSON, password string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(sendTransactionWithChainID, chainID, txArgsJSON, password)
|
|
|
|
}
|
|
|
|
|
|
|
|
// sendTransactionWithChainID converts RPC args and calls backend.SendTransactionWithChainID.
|
|
|
|
func sendTransactionWithChainID(chainID int, txArgsJSON, password string) string {
|
2022-06-09 13:09:56 +00:00
|
|
|
var params transactions.SendTxArgs
|
|
|
|
err := json.Unmarshal([]byte(txArgsJSON), ¶ms)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
hash, err := statusBackend.SendTransactionWithChainID(uint64(chainID), params, password)
|
|
|
|
code := codeUnknown
|
|
|
|
if c, ok := errToCodeMap[err]; ok {
|
|
|
|
code = c
|
|
|
|
}
|
|
|
|
return prepareJSONResponseWithCode(hash.String(), err, code)
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:02:52 +00:00
|
|
|
func SendTransaction(txArgsJSON, password string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(sendTransaction, txArgsJSON, password)
|
|
|
|
}
|
|
|
|
|
|
|
|
// sendTransaction converts RPC args and calls backend.SendTransaction.
|
|
|
|
func sendTransaction(txArgsJSON, password string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
var params transactions.SendTxArgs
|
|
|
|
err := json.Unmarshal([]byte(txArgsJSON), ¶ms)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
hash, err := statusBackend.SendTransaction(params, password)
|
|
|
|
code := codeUnknown
|
|
|
|
if c, ok := errToCodeMap[err]; ok {
|
|
|
|
code = c
|
|
|
|
}
|
|
|
|
return prepareJSONResponseWithCode(hash.String(), err, code)
|
|
|
|
}
|
|
|
|
|
2019-02-15 11:31:20 +00:00
|
|
|
func SendTransactionWithSignature(txArgsJSON, sigString string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(sendTransactionWithSignature, txArgsJSON, sigString)
|
|
|
|
}
|
|
|
|
|
|
|
|
// sendTransactionWithSignature converts RPC args and calls backend.SendTransactionWithSignature
|
|
|
|
func sendTransactionWithSignature(txArgsJSON, sigString string) string {
|
2019-02-15 11:31:20 +00:00
|
|
|
var params transactions.SendTxArgs
|
|
|
|
err := json.Unmarshal([]byte(txArgsJSON), ¶ms)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
|
|
|
|
sig, err := hex.DecodeString(sigString)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
|
|
|
|
hash, err := statusBackend.SendTransactionWithSignature(params, sig)
|
|
|
|
code := codeUnknown
|
|
|
|
if c, ok := errToCodeMap[err]; ok {
|
|
|
|
code = c
|
|
|
|
}
|
|
|
|
return prepareJSONResponseWithCode(hash.String(), err, code)
|
|
|
|
}
|
|
|
|
|
2019-02-21 09:53:39 +00:00
|
|
|
func HashTransaction(txArgsJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(hashTransaction, txArgsJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
// hashTransaction validate the transaction and returns new txArgs and the transaction hash.
|
|
|
|
func hashTransaction(txArgsJSON string) string {
|
2019-02-21 09:53:39 +00:00
|
|
|
var params transactions.SendTxArgs
|
|
|
|
err := json.Unmarshal([]byte(txArgsJSON), ¶ms)
|
|
|
|
if err != nil {
|
|
|
|
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
|
|
|
}
|
|
|
|
|
|
|
|
newTxArgs, hash, err := statusBackend.HashTransaction(params)
|
|
|
|
code := codeUnknown
|
|
|
|
if c, ok := errToCodeMap[err]; ok {
|
|
|
|
code = c
|
|
|
|
}
|
|
|
|
|
|
|
|
result := struct {
|
|
|
|
Transaction transactions.SendTxArgs `json:"transaction"`
|
2019-11-23 17:57:05 +00:00
|
|
|
Hash types.Hash `json:"hash"`
|
2019-02-21 09:53:39 +00:00
|
|
|
}{
|
|
|
|
Transaction: newTxArgs,
|
|
|
|
Hash: hash,
|
|
|
|
}
|
|
|
|
|
|
|
|
return prepareJSONResponseWithCode(result, err, code)
|
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func HashMessage(message string) string {
|
|
|
|
return logAndCallString(hashMessage, message)
|
|
|
|
}
|
|
|
|
|
|
|
|
// hashMessage calculates the hash of a message to be safely signed by the keycard
|
2019-03-21 10:48:47 +00:00
|
|
|
// The hash is calulcated as
|
2022-12-29 06:16:19 +00:00
|
|
|
//
|
|
|
|
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
|
|
|
|
//
|
2019-03-21 10:48:47 +00:00
|
|
|
// This gives context to the signed message and prevents signing of transactions.
|
2024-09-13 15:08:20 +00:00
|
|
|
func hashMessage(message string) string {
|
2019-04-29 23:26:41 +00:00
|
|
|
hash, err := api.HashMessage(message)
|
|
|
|
code := codeUnknown
|
|
|
|
if c, ok := errToCodeMap[err]; ok {
|
|
|
|
code = c
|
2019-03-21 10:48:47 +00:00
|
|
|
}
|
2019-04-29 23:26:41 +00:00
|
|
|
return prepareJSONResponseWithCode(fmt.Sprintf("0x%x", hash), err, code)
|
2019-03-21 10:48:47 +00:00
|
|
|
}
|
|
|
|
|
2019-02-01 17:02:52 +00:00
|
|
|
func StartCPUProfile(dataDir string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(startCPUProfile, dataDir)
|
|
|
|
}
|
|
|
|
|
|
|
|
// startCPUProfile runs pprof for CPU.
|
|
|
|
func startCPUProfile(dataDir string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
err := profiling.StartCPUProfile(dataDir)
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func StopCPUProfiling() string {
|
|
|
|
return logAndCallString(stopCPUProfiling)
|
|
|
|
}
|
|
|
|
|
|
|
|
// stopCPUProfiling stops pprof for cpu.
|
|
|
|
func stopCPUProfiling() string { //nolint: deadcode
|
2019-02-01 17:02:52 +00:00
|
|
|
err := profiling.StopCPUProfile()
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func WriteHeapProfile(dataDir string) string {
|
|
|
|
return logAndCallString(writeHeapProfile, dataDir)
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeHeapProfile starts pprof for heap
|
|
|
|
func writeHeapProfile(dataDir string) string { //nolint: deadcode
|
2019-02-01 17:02:52 +00:00
|
|
|
err := profiling.WriteHeapFile(dataDir)
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeJSONResponse(err error) string {
|
|
|
|
errString := ""
|
|
|
|
if err != nil {
|
2024-09-13 15:08:20 +00:00
|
|
|
log.Error("error in makeJSONResponse", "error", err)
|
2019-02-01 17:02:52 +00:00
|
|
|
errString = err.Error()
|
|
|
|
}
|
|
|
|
|
|
|
|
out := APIResponse{
|
|
|
|
Error: errString,
|
|
|
|
}
|
|
|
|
outBytes, _ := json.Marshal(out)
|
|
|
|
|
|
|
|
return string(outBytes)
|
|
|
|
}
|
|
|
|
|
|
|
|
func AddPeer(enode string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(addPeer, enode)
|
|
|
|
}
|
|
|
|
|
|
|
|
// addPeer adds an enode as a peer.
|
|
|
|
func addPeer(enode string) string {
|
2019-02-01 17:02:52 +00:00
|
|
|
err := statusBackend.StatusNode().AddPeer(enode)
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func ConnectionChange(typ string, expensive int) {
|
2024-09-13 15:08:20 +00:00
|
|
|
logAndCall(connectionChange, typ, expensive)
|
|
|
|
}
|
|
|
|
|
|
|
|
// connectionChange handles network state changes as reported
|
|
|
|
// by ReactNative (see https://facebook.github.io/react-native/docs/netinfo.html)
|
|
|
|
func connectionChange(typ string, expensive int) {
|
2019-02-01 17:02:52 +00:00
|
|
|
statusBackend.ConnectionChange(typ, expensive == 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func AppStateChange(state string) {
|
2024-09-13 15:08:20 +00:00
|
|
|
logAndCall(appStateChange, state)
|
|
|
|
}
|
|
|
|
|
|
|
|
// appStateChange handles app state changes (background/foreground).
|
|
|
|
func appStateChange(state string) {
|
2019-02-01 17:02:52 +00:00
|
|
|
statusBackend.AppStateChange(state)
|
|
|
|
}
|
|
|
|
|
2020-10-28 07:56:14 +00:00
|
|
|
func StartLocalNotifications() string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(startLocalNotifications)
|
|
|
|
}
|
|
|
|
|
|
|
|
// startLocalNotifications
|
|
|
|
func startLocalNotifications() string {
|
2020-10-28 07:56:14 +00:00
|
|
|
err := statusBackend.StartLocalNotifications()
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func StopLocalNotifications() string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(stopLocalNotifications)
|
|
|
|
}
|
|
|
|
|
|
|
|
// stopLocalNotifications
|
|
|
|
func stopLocalNotifications() string {
|
2020-10-28 07:56:14 +00:00
|
|
|
err := statusBackend.StopLocalNotifications()
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:02:52 +00:00
|
|
|
func SetMobileSignalHandler(handler SignalHandler) {
|
2024-09-13 15:08:20 +00:00
|
|
|
logAndCall(setMobileSignalHandler, handler)
|
|
|
|
}
|
|
|
|
|
|
|
|
// setMobileSignalHandler setup geth callback to notify about new signal
|
|
|
|
// used for gomobile builds
|
|
|
|
func setMobileSignalHandler(handler SignalHandler) {
|
2019-02-01 17:02:52 +00:00
|
|
|
signal.SetMobileSignalHandler(func(data []byte) {
|
|
|
|
if len(data) > 0 {
|
|
|
|
handler.HandleSignal(string(data))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetSignalEventCallback(cb unsafe.Pointer) {
|
2024-09-13 15:08:20 +00:00
|
|
|
logAndCall(setSignalEventCallback, cb)
|
|
|
|
}
|
|
|
|
|
|
|
|
// setSignalEventCallback setup geth callback to notify about new signal
|
|
|
|
func setSignalEventCallback(cb unsafe.Pointer) {
|
2019-02-01 17:02:52 +00:00
|
|
|
signal.SetSignalEventCallback(cb)
|
|
|
|
}
|
2019-02-12 11:07:13 +00:00
|
|
|
|
2019-03-04 14:33:48 +00:00
|
|
|
// ExportNodeLogs reads current node log and returns content to a caller.
|
2022-12-29 06:16:19 +00:00
|
|
|
//
|
2019-03-04 14:33:48 +00:00
|
|
|
//export ExportNodeLogs
|
|
|
|
func ExportNodeLogs() string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(exportNodeLogs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func exportNodeLogs() string {
|
2019-03-04 14:33:48 +00:00
|
|
|
node := statusBackend.StatusNode()
|
|
|
|
if node == nil {
|
|
|
|
return makeJSONResponse(errors.New("node is not running"))
|
|
|
|
}
|
|
|
|
config := node.Config()
|
|
|
|
if config == nil {
|
|
|
|
return makeJSONResponse(errors.New("config and log file are not available"))
|
|
|
|
}
|
|
|
|
data, err := json.Marshal(exportlogs.ExportFromBaseFile(config.LogFile))
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(fmt.Errorf("error marshalling to json: %v", err))
|
|
|
|
}
|
|
|
|
return string(data)
|
|
|
|
}
|
2019-03-21 12:02:16 +00:00
|
|
|
|
2019-04-18 13:52:08 +00:00
|
|
|
func SignHash(hexEncodedHash string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(signHash, hexEncodedHash)
|
|
|
|
}
|
|
|
|
|
|
|
|
// signHash exposes vanilla ECDSA signing required for Swarm messages
|
|
|
|
func signHash(hexEncodedHash string) string {
|
2019-04-18 13:52:08 +00:00
|
|
|
hexEncodedSignature, err := statusBackend.SignHash(hexEncodedHash)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return hexEncodedSignature
|
|
|
|
}
|
2019-09-26 07:01:17 +00:00
|
|
|
|
|
|
|
func GenerateAlias(pk string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(generateAlias, pk)
|
|
|
|
}
|
|
|
|
|
|
|
|
func generateAlias(pk string) string {
|
2019-09-26 07:01:17 +00:00
|
|
|
// We ignore any error, empty string is considered an error
|
|
|
|
name, _ := protocol.GenerateAlias(pk)
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
|
2022-02-17 15:13:10 +00:00
|
|
|
func IsAlias(value string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(isAlias, value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func isAlias(value string) string {
|
2022-02-17 15:13:10 +00:00
|
|
|
return prepareJSONResponse(alias.IsAlias(value), nil)
|
|
|
|
}
|
|
|
|
|
2019-09-26 07:01:17 +00:00
|
|
|
func Identicon(pk string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(identicon, pk)
|
|
|
|
}
|
|
|
|
|
|
|
|
func identicon(pk string) string {
|
2019-09-26 07:01:17 +00:00
|
|
|
// We ignore any error, empty string is considered an error
|
|
|
|
identicon, _ := protocol.Identicon(pk)
|
|
|
|
return identicon
|
|
|
|
}
|
2019-12-16 13:55:02 +00:00
|
|
|
|
2022-03-17 16:58:35 +00:00
|
|
|
func EmojiHash(pk string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(emojiHash, pk)
|
|
|
|
}
|
|
|
|
|
|
|
|
func emojiHash(pk string) string {
|
2022-03-17 16:58:35 +00:00
|
|
|
return prepareJSONResponse(emojihash.GenerateFor(pk))
|
|
|
|
}
|
|
|
|
|
|
|
|
func ColorHash(pk string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(colorHash, pk)
|
|
|
|
}
|
|
|
|
|
|
|
|
func colorHash(pk string) string {
|
2022-03-17 16:58:35 +00:00
|
|
|
return prepareJSONResponse(colorhash.GenerateFor(pk))
|
|
|
|
}
|
|
|
|
|
2022-04-08 17:54:29 +00:00
|
|
|
func ColorID(pk string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(colorID, pk)
|
|
|
|
}
|
|
|
|
|
|
|
|
func colorID(pk string) string {
|
2022-04-08 17:54:29 +00:00
|
|
|
return prepareJSONResponse(identityUtils.ToColorID(pk))
|
|
|
|
}
|
|
|
|
|
2019-12-16 13:55:02 +00:00
|
|
|
func ValidateMnemonic(mnemonic string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(validateMnemonic, mnemonic)
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateMnemonic(mnemonic string) string {
|
2019-12-16 13:55:02 +00:00
|
|
|
m := extkeys.NewMnemonic()
|
|
|
|
err := m.ValidateMnemonic(mnemonic, extkeys.Language(0))
|
2023-03-28 08:12:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
keyUID, err := statusBackend.GetKeyUIDByMnemonic(mnemonic)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
response := &APIKeyUIDResponse{KeyUID: keyUID}
|
|
|
|
data, err := json.Marshal(response)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return string(data)
|
2019-12-16 13:55:02 +00:00
|
|
|
}
|
2020-06-23 10:47:17 +00:00
|
|
|
|
2022-10-25 09:32:26 +00:00
|
|
|
func DecompressPublicKey(key string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(decompressPublicKey, key)
|
|
|
|
}
|
|
|
|
|
|
|
|
// decompressPublicKey decompresses 33-byte compressed format to uncompressed 65-byte format.
|
|
|
|
func decompressPublicKey(key string) string {
|
2022-10-25 09:32:26 +00:00
|
|
|
decoded, err := types.DecodeHex(key)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
const compressionBytesNumber = 33
|
|
|
|
if len(decoded) != compressionBytesNumber {
|
|
|
|
return makeJSONResponse(errors.New("key is not 33 bytes long"))
|
|
|
|
}
|
|
|
|
pubKey, err := crypto.DecompressPubkey(decoded)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return types.EncodeHex(crypto.FromECDSAPub(pubKey))
|
|
|
|
}
|
|
|
|
|
|
|
|
func CompressPublicKey(key string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(compressPublicKey, key)
|
|
|
|
}
|
|
|
|
|
|
|
|
// compressPublicKey compresses uncompressed 65-byte format to 33-byte compressed format.
|
|
|
|
func compressPublicKey(key string) string {
|
2022-10-25 09:32:26 +00:00
|
|
|
pubKey, err := common.HexToPubkey(key)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return types.EncodeHex(crypto.CompressPubkey(pubKey))
|
|
|
|
}
|
|
|
|
|
2023-01-20 18:51:36 +00:00
|
|
|
func SerializeLegacyKey(key string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(serializeLegacyKey, key)
|
|
|
|
}
|
|
|
|
|
|
|
|
// serializeLegacyKey compresses an old format public key (0x04...) to the new one zQ...
|
|
|
|
func serializeLegacyKey(key string) string {
|
2023-01-20 18:51:36 +00:00
|
|
|
cpk, err := multiformat.SerializeLegacyKey(key)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return cpk
|
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func MultiformatSerializePublicKey(key, outBase string) string {
|
|
|
|
return logAndCallString(multiformatSerializePublicKey, key, outBase)
|
|
|
|
}
|
|
|
|
|
2020-06-23 10:47:17 +00:00
|
|
|
// SerializePublicKey compresses an uncompressed multibase encoded multicodec identified EC public key
|
2020-06-24 13:39:42 +00:00
|
|
|
// For details on usage see specs https://specs.status.im/spec/2#public-key-serialization
|
2024-09-13 15:08:20 +00:00
|
|
|
func multiformatSerializePublicKey(key, outBase string) string {
|
2020-06-23 10:47:17 +00:00
|
|
|
cpk, err := multiformat.SerializePublicKey(key, outBase)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return cpk
|
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func MultiformatDeserializePublicKey(key, outBase string) string {
|
|
|
|
return logAndCallString(multiformatDeserializePublicKey, key, outBase)
|
|
|
|
}
|
|
|
|
|
2020-06-23 10:47:17 +00:00
|
|
|
// DeserializePublicKey decompresses a compressed multibase encoded multicodec identified EC public key
|
2020-06-24 13:39:42 +00:00
|
|
|
// For details on usage see specs https://specs.status.im/spec/2#public-key-serialization
|
2024-09-13 15:08:20 +00:00
|
|
|
func multiformatDeserializePublicKey(key, outBase string) string {
|
2020-06-23 10:47:17 +00:00
|
|
|
pk, err := multiformat.DeserializePublicKey(key, outBase)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return pk
|
|
|
|
}
|
2021-01-07 11:15:02 +00:00
|
|
|
|
|
|
|
func ExportUnencryptedDatabase(accountData, password, databasePath string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(exportUnencryptedDatabase, accountData, password, databasePath)
|
|
|
|
}
|
|
|
|
|
|
|
|
// exportUnencryptedDatabase exports the database unencrypted to the given path
|
|
|
|
func exportUnencryptedDatabase(accountData, password, databasePath string) string {
|
2021-01-07 11:15:02 +00:00
|
|
|
var account multiaccounts.Account
|
|
|
|
err := json.Unmarshal([]byte(accountData), &account)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
err = statusBackend.ExportUnencryptedDatabase(account, password, databasePath)
|
2024-09-13 15:08:20 +00:00
|
|
|
return makeJSONResponse(err)
|
2021-01-07 11:15:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func ImportUnencryptedDatabase(accountData, password, databasePath string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(importUnencryptedDatabase, accountData, password, databasePath)
|
|
|
|
}
|
|
|
|
|
|
|
|
// importUnencryptedDatabase imports the database unencrypted to the given directory
|
|
|
|
func importUnencryptedDatabase(accountData, password, databasePath string) string {
|
2021-01-07 11:15:02 +00:00
|
|
|
var account multiaccounts.Account
|
|
|
|
err := json.Unmarshal([]byte(accountData), &account)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
err = statusBackend.ImportUnencryptedDatabase(account, password, databasePath)
|
2024-09-13 15:08:20 +00:00
|
|
|
return makeJSONResponse(err)
|
2021-01-07 11:15:02 +00:00
|
|
|
}
|
2021-06-23 09:21:21 +00:00
|
|
|
|
2022-09-05 11:52:53 +00:00
|
|
|
func ChangeDatabasePassword(KeyUID, password, newPassword string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(changeDatabasePassword, KeyUID, password, newPassword)
|
|
|
|
}
|
|
|
|
|
|
|
|
// changeDatabasePassword changes the password of the database
|
|
|
|
func changeDatabasePassword(KeyUID, password, newPassword string) string {
|
2022-09-05 11:52:53 +00:00
|
|
|
err := statusBackend.ChangeDatabasePassword(KeyUID, password, newPassword)
|
2024-09-13 15:08:20 +00:00
|
|
|
return makeJSONResponse(err)
|
2021-06-23 09:21:21 +00:00
|
|
|
}
|
2021-07-20 11:48:10 +00:00
|
|
|
|
2023-05-05 07:43:05 +00:00
|
|
|
func ConvertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(convertToKeycardAccount, accountData, settingsJSON, keycardUID, password, newPassword)
|
|
|
|
}
|
|
|
|
|
|
|
|
// convertToKeycardAccount converts the account to a keycard account
|
|
|
|
func convertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword string) string {
|
2021-07-20 11:48:10 +00:00
|
|
|
var account multiaccounts.Account
|
|
|
|
err := json.Unmarshal([]byte(accountData), &account)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2022-03-23 18:47:00 +00:00
|
|
|
var settings settings.Settings
|
2021-07-20 11:48:10 +00:00
|
|
|
err = json.Unmarshal([]byte(settingsJSON), &settings)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2023-05-05 07:43:05 +00:00
|
|
|
err = statusBackend.ConvertToKeycardAccount(account, settings, keycardUID, password, newPassword)
|
2024-09-13 15:08:20 +00:00
|
|
|
return makeJSONResponse(err)
|
2021-07-20 11:48:10 +00:00
|
|
|
}
|
2022-02-10 17:19:34 +00:00
|
|
|
|
2023-01-25 10:25:07 +00:00
|
|
|
func ConvertToRegularAccount(mnemonic, currPassword, newPassword string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(convertToRegularAccount, mnemonic, currPassword, newPassword)
|
|
|
|
}
|
|
|
|
|
|
|
|
// convertToRegularAccount converts the account to a regular account
|
|
|
|
func convertToRegularAccount(mnemonic, currPassword, newPassword string) string {
|
2023-01-25 10:25:07 +00:00
|
|
|
err := statusBackend.ConvertToRegularAccount(mnemonic, currPassword, newPassword)
|
2024-09-13 15:08:20 +00:00
|
|
|
return makeJSONResponse(err)
|
2023-01-25 10:25:07 +00:00
|
|
|
}
|
|
|
|
|
2022-02-10 17:19:34 +00:00
|
|
|
func ImageServerTLSCert() string {
|
2023-06-02 02:44:24 +00:00
|
|
|
cert, err := server.PublicMediaTLSCert()
|
2022-02-10 17:19:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return cert
|
|
|
|
}
|
2022-03-18 12:20:13 +00:00
|
|
|
|
2022-03-23 14:19:19 +00:00
|
|
|
type GetPasswordStrengthRequest struct {
|
|
|
|
Password string `json:"password"`
|
|
|
|
UserInputs []string `json:"userInputs"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type PasswordScoreResponse struct {
|
|
|
|
Score int `json:"score"`
|
|
|
|
}
|
|
|
|
|
2022-03-18 12:20:13 +00:00
|
|
|
// GetPasswordStrength uses zxcvbn module and generates a JSON containing information about the quality of the given password
|
|
|
|
// (Entropy, CrackTime, CrackTimeDisplay, Score, MatchSequence and CalcTime).
|
|
|
|
// userInputs argument can be whatever list of strings like user's personal info or site-specific vocabulary that zxcvbn will
|
|
|
|
// make use to determine the result.
|
|
|
|
// For more details on usage see https://github.com/status-im/zxcvbn-go
|
|
|
|
func GetPasswordStrength(paramsJSON string) string {
|
2022-03-23 14:19:19 +00:00
|
|
|
var requestParams GetPasswordStrengthRequest
|
|
|
|
|
|
|
|
err := json.Unmarshal([]byte(paramsJSON), &requestParams)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
2022-03-18 12:20:13 +00:00
|
|
|
}
|
|
|
|
|
2022-03-23 14:19:19 +00:00
|
|
|
data, err := json.Marshal(zxcvbn.PasswordStrength(requestParams.Password, requestParams.UserInputs))
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err))
|
|
|
|
}
|
|
|
|
return string(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPasswordStrengthScore uses zxcvbn module and gets the score information about the given password.
|
|
|
|
// userInputs argument can be whatever list of strings like user's personal info or site-specific vocabulary that zxcvbn will
|
|
|
|
// make use to determine the result.
|
|
|
|
// For more details on usage see https://github.com/status-im/zxcvbn-go
|
|
|
|
func GetPasswordStrengthScore(paramsJSON string) string {
|
|
|
|
var requestParams GetPasswordStrengthRequest
|
|
|
|
var quality scoring.MinEntropyMatch
|
|
|
|
|
|
|
|
err := json.Unmarshal([]byte(paramsJSON), &requestParams)
|
2022-03-18 12:20:13 +00:00
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2022-03-23 14:19:19 +00:00
|
|
|
quality = zxcvbn.PasswordStrength(requestParams.Password, requestParams.UserInputs)
|
|
|
|
|
|
|
|
data, err := json.Marshal(PasswordScoreResponse{
|
|
|
|
Score: quality.Score,
|
|
|
|
})
|
2022-03-18 12:20:13 +00:00
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err))
|
|
|
|
}
|
|
|
|
return string(data)
|
|
|
|
}
|
2022-03-17 18:06:02 +00:00
|
|
|
|
2023-12-07 13:45:53 +00:00
|
|
|
type FleetDescription struct {
|
2024-05-26 23:16:26 +00:00
|
|
|
DefaultFleet string `json:"defaultFleet"`
|
|
|
|
Fleets map[string]map[string][]string `json:"fleets"`
|
2023-12-07 13:45:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func Fleets() string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(fleets)
|
|
|
|
}
|
|
|
|
|
|
|
|
func fleets() string {
|
2023-12-07 13:45:53 +00:00
|
|
|
fleets := FleetDescription{
|
|
|
|
DefaultFleet: api.DefaultFleet,
|
2024-02-22 19:32:24 +00:00
|
|
|
Fleets: params.GetSupportedFleets(),
|
2023-12-07 13:45:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data, err := json.Marshal(fleets)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err))
|
|
|
|
}
|
|
|
|
return string(data)
|
|
|
|
}
|
|
|
|
|
2022-03-17 18:06:02 +00:00
|
|
|
func SwitchFleet(fleet string, configJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(switchFleet, fleet, configJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
func switchFleet(fleet string, configJSON string) string {
|
2022-03-17 18:06:02 +00:00
|
|
|
var conf params.NodeConfig
|
|
|
|
if configJSON != "" {
|
|
|
|
err := json.Unmarshal([]byte(configJSON), &conf)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-23 12:54:51 +00:00
|
|
|
clusterConfig, err := params.LoadClusterConfigFromFleet(fleet)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2022-03-17 18:06:02 +00:00
|
|
|
conf.ClusterConfig.Fleet = fleet
|
2023-11-23 12:54:51 +00:00
|
|
|
conf.ClusterConfig.ClusterID = clusterConfig.ClusterID
|
2022-03-17 18:06:02 +00:00
|
|
|
|
2023-11-23 12:54:51 +00:00
|
|
|
err = statusBackend.SwitchFleet(fleet, &conf)
|
2022-03-17 18:06:02 +00:00
|
|
|
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2022-04-06 11:08:52 +00:00
|
|
|
|
|
|
|
func GenerateImages(filepath string, aX, aY, bX, bY int) string {
|
|
|
|
iis, err := images.GenerateIdentityImages(filepath, aX, aY, bX, bY)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := json.Marshal(iis)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(fmt.Errorf("Error marshalling to json: %v", err))
|
|
|
|
}
|
|
|
|
return string(data)
|
|
|
|
}
|
2022-08-31 11:44:12 +00:00
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func LocalPairingPreflightOutboundCheck() string {
|
|
|
|
return logAndCallString(localPairingPreflightOutboundCheck)
|
|
|
|
}
|
|
|
|
|
|
|
|
// localPairingPreflightOutboundCheck creates a local tls server accessible via an outbound network address.
|
2023-06-02 03:05:51 +00:00
|
|
|
// The function creates a client and makes an outbound network call to the local server. This function should be
|
|
|
|
// triggered to ensure that the device has permissions to access its LAN or to make outbound network calls.
|
|
|
|
//
|
|
|
|
// In addition, the functionality attempts to address an issue with iOS devices https://stackoverflow.com/a/64242745
|
2024-09-13 15:08:20 +00:00
|
|
|
func localPairingPreflightOutboundCheck() string {
|
2023-06-02 03:05:51 +00:00
|
|
|
err := preflight.CheckOutbound()
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func StartSearchForLocalPairingPeers() string {
|
|
|
|
return logAndCallString(startSearchForLocalPairingPeers)
|
|
|
|
}
|
|
|
|
|
|
|
|
// startSearchForLocalPairingPeers starts a UDP multicast beacon that both listens for and broadcasts to LAN peers
|
2023-04-12 10:30:12 +00:00
|
|
|
// on discovery the beacon will emit a signal with the details of the discovered peer.
|
|
|
|
//
|
|
|
|
// Currently, beacons are configured to search for 2 minutes pinging the network every 500 ms;
|
|
|
|
// - If no peer discovery is made before this time elapses the operation will terminate.
|
|
|
|
// - If a peer is discovered the pairing.PeerNotifier will terminate operation after 5 seconds, giving the peer
|
|
|
|
// reasonable time to discover this device.
|
|
|
|
//
|
|
|
|
// Peer details are represented by a json.Marshal peers.LocalPairingPeerHello
|
2024-09-13 15:08:20 +00:00
|
|
|
func startSearchForLocalPairingPeers() string {
|
2023-04-12 10:30:12 +00:00
|
|
|
pn := pairing.NewPeerNotifier()
|
|
|
|
err := pn.Search()
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func GetConnectionStringForBeingBootstrapped(configJSON string) string {
|
|
|
|
return logAndCallString(getConnectionStringForBeingBootstrapped, configJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
// getConnectionStringForBeingBootstrapped starts a pairing.ReceiverServer
|
2023-01-06 12:21:14 +00:00
|
|
|
// then generates a pairing.ConnectionParams. Used when the device is Logged out or has no Account keys
|
2022-08-31 11:44:12 +00:00
|
|
|
// and the device has no camera to read a QR code with
|
|
|
|
//
|
|
|
|
// Example: A desktop device (device without camera) receiving account data from mobile (device with camera)
|
2024-09-13 15:08:20 +00:00
|
|
|
func getConnectionStringForBeingBootstrapped(configJSON string) string {
|
2022-09-21 14:04:14 +00:00
|
|
|
if configJSON == "" {
|
2023-01-06 12:21:14 +00:00
|
|
|
return makeJSONResponse(fmt.Errorf("no config given, PayloadSourceConfig is expected"))
|
2022-08-31 12:47:16 +00:00
|
|
|
}
|
2023-06-01 05:33:57 +00:00
|
|
|
|
2023-07-12 22:29:38 +00:00
|
|
|
statusBackend.LocalPairingStateManager.SetPairing(true)
|
2023-06-01 05:33:57 +00:00
|
|
|
defer func() {
|
2023-07-12 22:29:38 +00:00
|
|
|
statusBackend.LocalPairingStateManager.SetPairing(false)
|
2023-06-01 05:33:57 +00:00
|
|
|
}()
|
|
|
|
|
2023-03-21 13:08:28 +00:00
|
|
|
cs, err := pairing.StartUpReceiverServer(statusBackend, configJSON)
|
2022-08-31 12:47:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2023-06-01 05:33:57 +00:00
|
|
|
|
|
|
|
err = statusBackend.Logout()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2022-08-31 12:47:16 +00:00
|
|
|
return cs
|
2022-08-31 11:44:12 +00:00
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func GetConnectionStringForBootstrappingAnotherDevice(configJSON string) string {
|
|
|
|
return logAndCallString(getConnectionStringForBootstrappingAnotherDevice, configJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
// getConnectionStringForBootstrappingAnotherDevice starts a pairing.SenderServer
|
2023-01-06 12:21:14 +00:00
|
|
|
// then generates a pairing.ConnectionParams. Used when the device is Logged in and therefore has Account keys
|
2022-08-31 11:44:12 +00:00
|
|
|
// and the device might not have a camera
|
|
|
|
//
|
|
|
|
// Example: A mobile or desktop device (devices that MAY have a camera but MUST have a screen)
|
|
|
|
// sending account data to a mobile (device with camera)
|
2024-09-13 15:08:20 +00:00
|
|
|
func getConnectionStringForBootstrappingAnotherDevice(configJSON string) string {
|
2022-09-21 14:04:14 +00:00
|
|
|
if configJSON == "" {
|
2023-03-23 11:44:15 +00:00
|
|
|
return makeJSONResponse(fmt.Errorf("no config given, SendingServerConfig is expected"))
|
2022-08-31 12:47:16 +00:00
|
|
|
}
|
2023-06-01 05:33:57 +00:00
|
|
|
|
2023-07-12 22:29:38 +00:00
|
|
|
statusBackend.LocalPairingStateManager.SetPairing(true)
|
2023-06-01 05:33:57 +00:00
|
|
|
defer func() {
|
2023-07-12 22:29:38 +00:00
|
|
|
statusBackend.LocalPairingStateManager.SetPairing(false)
|
2023-06-01 05:33:57 +00:00
|
|
|
}()
|
|
|
|
|
2023-03-21 13:08:28 +00:00
|
|
|
cs, err := pairing.StartUpSenderServer(statusBackend, configJSON)
|
2022-08-31 12:47:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return cs
|
2022-08-31 11:44:12 +00:00
|
|
|
}
|
|
|
|
|
feat: fallback pairing seed (#5614)
* feat(pairing)!: Add extra parameters and remove v2 compatibility
This commit includes the following changes:
I have added a flag to maintain 2.29 compatibility.
Breaking change in connection string
The local pairing code that was parsing the connection string had a few non-upgradable features:
It was strictly checking the number of parameters, throwing an error if the number was different. This made it impossible to add parameters to it without breaking.
It was strictly checking the version number. This made increasing the version number impossible as older client would just refuse to connect.
The code has been changed so that:
Two parameters have been added, installation-id and key-uid. Those are needed for the fallback flow.
I have also removed version from the payload, since it wasn't used.
This means that we don't support v1 anymore. V2 parsing is supported . Going forward there's a clear strategy on how to update the protocol (append parameters, don't change existing one).
https://www.youtube.com/watch?v=oyLBGkS5ICk Is a must watch video for understanding the strategy
Changed MessengerResponse to use internally a map of installations rather than an array (minor)
Just moving towards maps as arrays tend to lead to subtle bugs.
Moved pairing methods to messenger_pairing.go
Just moved some methods
Added 2 new methods for the fallback flow
FinishPairingThroughSeedPhraseProcess
https://github.com/status-im/status-go/pull/5567/files#diff-1ad620b07fa3bd5fbc96c9f459d88829938a162bf1aaf41c61dea6e38b488d54R29
EnableAndSyncInstallation
https://github.com/status-im/status-go/pull/5567/files#diff-1ad620b07fa3bd5fbc96c9f459d88829938a162bf1aaf41c61dea6e38b488d54R18
Flow for clients
Client A1 is logged in
Client A2 is logged out
Client A1 shows a QR code
Client A2 scans a QR code
If connection fails on A2, the user will be prompted to enter a seed phrase.
If the generated account matches the key-uid from the QR code, A2 should call FinishPairingThroughSeedPhraseProcess with the installation id passed in the QR code. This will send installation information over waku. The user should be shown its own installation id and prompted to check the other device.
Client A1 will receive new installation data through waku, if they are still on the qr code page, they should show a popup to the user showing the received installation id, and a way to Enable and Sync, which should call the EnableAndSyncInstallation endpoint. This should finish the fallback syncing flow.
Current issues
Currently I haven't tested that all the data is synced after finishing the flow. I see that the two devices are paired correctly, but for example the DisplayName is not changed on the receiving device. I haven't had time to look into it further.
* test_: add more test for connection string parser
* fix_: fix panic when parse old connection string
* test_: add comments for TestMessengerPairAfterSeedPhrase
* fix_: correct error description
* feat_:rename FinishPairingThroughSeedPhraseProcess to EnableInstallationAndPair
* fix_: delete leftover
* fix_: add UniqueKey method
* fix_: unify the response for InputConnectionStringForBootstrapping
* fix_: remove fields installationID and keyUID in GethStatusBackend
* fix_: rename messenger_pairing to messenger_pairing_and_syncing
---------
Co-authored-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2024-07-30 09:14:05 +00:00
|
|
|
type inputConnectionStringForBootstrappingResponse struct {
|
|
|
|
InstallationID string `json:"installationId"`
|
|
|
|
KeyUID string `json:"keyUID"`
|
|
|
|
Error error `json:"error"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *inputConnectionStringForBootstrappingResponse) toJSON(err error) string {
|
|
|
|
i.Error = err
|
|
|
|
j, _ := json.Marshal(i)
|
|
|
|
return string(j)
|
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func InputConnectionStringForBootstrapping(cs, configJSON string) string {
|
|
|
|
return logAndCallString(inputConnectionStringForBootstrapping, cs, configJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
// inputConnectionStringForBootstrapping starts a pairing.ReceiverClient
|
2022-08-31 14:01:45 +00:00
|
|
|
// The given server.ConnectionParams string will determine the server.Mode
|
|
|
|
//
|
|
|
|
// server.Mode = server.Sending
|
2022-08-31 12:47:16 +00:00
|
|
|
// Used when the device is Logged out or has no Account keys and has a camera to read a QR code
|
2022-08-31 11:44:12 +00:00
|
|
|
//
|
|
|
|
// Example: A mobile device (device with a camera) receiving account data from
|
|
|
|
// a device with a screen (mobile or desktop devices)
|
2024-09-13 15:08:20 +00:00
|
|
|
func inputConnectionStringForBootstrapping(cs, configJSON string) string {
|
2023-07-12 22:29:38 +00:00
|
|
|
var err error
|
2022-09-21 14:04:14 +00:00
|
|
|
if configJSON == "" {
|
2023-03-23 11:44:15 +00:00
|
|
|
return makeJSONResponse(fmt.Errorf("no config given, ReceiverClientConfig is expected"))
|
|
|
|
}
|
|
|
|
|
feat: fallback pairing seed (#5614)
* feat(pairing)!: Add extra parameters and remove v2 compatibility
This commit includes the following changes:
I have added a flag to maintain 2.29 compatibility.
Breaking change in connection string
The local pairing code that was parsing the connection string had a few non-upgradable features:
It was strictly checking the number of parameters, throwing an error if the number was different. This made it impossible to add parameters to it without breaking.
It was strictly checking the version number. This made increasing the version number impossible as older client would just refuse to connect.
The code has been changed so that:
Two parameters have been added, installation-id and key-uid. Those are needed for the fallback flow.
I have also removed version from the payload, since it wasn't used.
This means that we don't support v1 anymore. V2 parsing is supported . Going forward there's a clear strategy on how to update the protocol (append parameters, don't change existing one).
https://www.youtube.com/watch?v=oyLBGkS5ICk Is a must watch video for understanding the strategy
Changed MessengerResponse to use internally a map of installations rather than an array (minor)
Just moving towards maps as arrays tend to lead to subtle bugs.
Moved pairing methods to messenger_pairing.go
Just moved some methods
Added 2 new methods for the fallback flow
FinishPairingThroughSeedPhraseProcess
https://github.com/status-im/status-go/pull/5567/files#diff-1ad620b07fa3bd5fbc96c9f459d88829938a162bf1aaf41c61dea6e38b488d54R29
EnableAndSyncInstallation
https://github.com/status-im/status-go/pull/5567/files#diff-1ad620b07fa3bd5fbc96c9f459d88829938a162bf1aaf41c61dea6e38b488d54R18
Flow for clients
Client A1 is logged in
Client A2 is logged out
Client A1 shows a QR code
Client A2 scans a QR code
If connection fails on A2, the user will be prompted to enter a seed phrase.
If the generated account matches the key-uid from the QR code, A2 should call FinishPairingThroughSeedPhraseProcess with the installation id passed in the QR code. This will send installation information over waku. The user should be shown its own installation id and prompted to check the other device.
Client A1 will receive new installation data through waku, if they are still on the qr code page, they should show a popup to the user showing the received installation id, and a way to Enable and Sync, which should call the EnableAndSyncInstallation endpoint. This should finish the fallback syncing flow.
Current issues
Currently I haven't tested that all the data is synced after finishing the flow. I see that the two devices are paired correctly, but for example the DisplayName is not changed on the receiving device. I haven't had time to look into it further.
* test_: add more test for connection string parser
* fix_: fix panic when parse old connection string
* test_: add comments for TestMessengerPairAfterSeedPhrase
* fix_: correct error description
* feat_:rename FinishPairingThroughSeedPhraseProcess to EnableInstallationAndPair
* fix_: delete leftover
* fix_: add UniqueKey method
* fix_: unify the response for InputConnectionStringForBootstrapping
* fix_: remove fields installationID and keyUID in GethStatusBackend
* fix_: rename messenger_pairing to messenger_pairing_and_syncing
---------
Co-authored-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2024-07-30 09:14:05 +00:00
|
|
|
params := &pairing.ConnectionParams{}
|
|
|
|
err = params.FromString(cs)
|
|
|
|
if err != nil {
|
|
|
|
response := &inputConnectionStringForBootstrappingResponse{}
|
|
|
|
return response.toJSON(fmt.Errorf("could not parse connection string"))
|
|
|
|
}
|
|
|
|
response := &inputConnectionStringForBootstrappingResponse{
|
|
|
|
InstallationID: params.InstallationID(),
|
|
|
|
KeyUID: params.KeyUID(),
|
|
|
|
}
|
|
|
|
|
2023-07-12 22:29:38 +00:00
|
|
|
err = statusBackend.LocalPairingStateManager.StartPairing(cs)
|
|
|
|
defer func() { statusBackend.LocalPairingStateManager.StopPairing(cs, err) }()
|
|
|
|
if err != nil {
|
feat: fallback pairing seed (#5614)
* feat(pairing)!: Add extra parameters and remove v2 compatibility
This commit includes the following changes:
I have added a flag to maintain 2.29 compatibility.
Breaking change in connection string
The local pairing code that was parsing the connection string had a few non-upgradable features:
It was strictly checking the number of parameters, throwing an error if the number was different. This made it impossible to add parameters to it without breaking.
It was strictly checking the version number. This made increasing the version number impossible as older client would just refuse to connect.
The code has been changed so that:
Two parameters have been added, installation-id and key-uid. Those are needed for the fallback flow.
I have also removed version from the payload, since it wasn't used.
This means that we don't support v1 anymore. V2 parsing is supported . Going forward there's a clear strategy on how to update the protocol (append parameters, don't change existing one).
https://www.youtube.com/watch?v=oyLBGkS5ICk Is a must watch video for understanding the strategy
Changed MessengerResponse to use internally a map of installations rather than an array (minor)
Just moving towards maps as arrays tend to lead to subtle bugs.
Moved pairing methods to messenger_pairing.go
Just moved some methods
Added 2 new methods for the fallback flow
FinishPairingThroughSeedPhraseProcess
https://github.com/status-im/status-go/pull/5567/files#diff-1ad620b07fa3bd5fbc96c9f459d88829938a162bf1aaf41c61dea6e38b488d54R29
EnableAndSyncInstallation
https://github.com/status-im/status-go/pull/5567/files#diff-1ad620b07fa3bd5fbc96c9f459d88829938a162bf1aaf41c61dea6e38b488d54R18
Flow for clients
Client A1 is logged in
Client A2 is logged out
Client A1 shows a QR code
Client A2 scans a QR code
If connection fails on A2, the user will be prompted to enter a seed phrase.
If the generated account matches the key-uid from the QR code, A2 should call FinishPairingThroughSeedPhraseProcess with the installation id passed in the QR code. This will send installation information over waku. The user should be shown its own installation id and prompted to check the other device.
Client A1 will receive new installation data through waku, if they are still on the qr code page, they should show a popup to the user showing the received installation id, and a way to Enable and Sync, which should call the EnableAndSyncInstallation endpoint. This should finish the fallback syncing flow.
Current issues
Currently I haven't tested that all the data is synced after finishing the flow. I see that the two devices are paired correctly, but for example the DisplayName is not changed on the receiving device. I haven't had time to look into it further.
* test_: add more test for connection string parser
* fix_: fix panic when parse old connection string
* test_: add comments for TestMessengerPairAfterSeedPhrase
* fix_: correct error description
* feat_:rename FinishPairingThroughSeedPhraseProcess to EnableInstallationAndPair
* fix_: delete leftover
* fix_: add UniqueKey method
* fix_: unify the response for InputConnectionStringForBootstrapping
* fix_: remove fields installationID and keyUID in GethStatusBackend
* fix_: rename messenger_pairing to messenger_pairing_and_syncing
---------
Co-authored-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2024-07-30 09:14:05 +00:00
|
|
|
return response.toJSON(err)
|
2023-07-12 22:29:38 +00:00
|
|
|
}
|
2023-06-01 05:33:57 +00:00
|
|
|
|
2023-07-12 22:29:38 +00:00
|
|
|
err = pairing.StartUpReceivingClient(statusBackend, cs, configJSON)
|
2023-06-01 05:33:57 +00:00
|
|
|
if err != nil {
|
feat: fallback pairing seed (#5614)
* feat(pairing)!: Add extra parameters and remove v2 compatibility
This commit includes the following changes:
I have added a flag to maintain 2.29 compatibility.
Breaking change in connection string
The local pairing code that was parsing the connection string had a few non-upgradable features:
It was strictly checking the number of parameters, throwing an error if the number was different. This made it impossible to add parameters to it without breaking.
It was strictly checking the version number. This made increasing the version number impossible as older client would just refuse to connect.
The code has been changed so that:
Two parameters have been added, installation-id and key-uid. Those are needed for the fallback flow.
I have also removed version from the payload, since it wasn't used.
This means that we don't support v1 anymore. V2 parsing is supported . Going forward there's a clear strategy on how to update the protocol (append parameters, don't change existing one).
https://www.youtube.com/watch?v=oyLBGkS5ICk Is a must watch video for understanding the strategy
Changed MessengerResponse to use internally a map of installations rather than an array (minor)
Just moving towards maps as arrays tend to lead to subtle bugs.
Moved pairing methods to messenger_pairing.go
Just moved some methods
Added 2 new methods for the fallback flow
FinishPairingThroughSeedPhraseProcess
https://github.com/status-im/status-go/pull/5567/files#diff-1ad620b07fa3bd5fbc96c9f459d88829938a162bf1aaf41c61dea6e38b488d54R29
EnableAndSyncInstallation
https://github.com/status-im/status-go/pull/5567/files#diff-1ad620b07fa3bd5fbc96c9f459d88829938a162bf1aaf41c61dea6e38b488d54R18
Flow for clients
Client A1 is logged in
Client A2 is logged out
Client A1 shows a QR code
Client A2 scans a QR code
If connection fails on A2, the user will be prompted to enter a seed phrase.
If the generated account matches the key-uid from the QR code, A2 should call FinishPairingThroughSeedPhraseProcess with the installation id passed in the QR code. This will send installation information over waku. The user should be shown its own installation id and prompted to check the other device.
Client A1 will receive new installation data through waku, if they are still on the qr code page, they should show a popup to the user showing the received installation id, and a way to Enable and Sync, which should call the EnableAndSyncInstallation endpoint. This should finish the fallback syncing flow.
Current issues
Currently I haven't tested that all the data is synced after finishing the flow. I see that the two devices are paired correctly, but for example the DisplayName is not changed on the receiving device. I haven't had time to look into it further.
* test_: add more test for connection string parser
* fix_: fix panic when parse old connection string
* test_: add comments for TestMessengerPairAfterSeedPhrase
* fix_: correct error description
* feat_:rename FinishPairingThroughSeedPhraseProcess to EnableInstallationAndPair
* fix_: delete leftover
* fix_: add UniqueKey method
* fix_: unify the response for InputConnectionStringForBootstrapping
* fix_: remove fields installationID and keyUID in GethStatusBackend
* fix_: rename messenger_pairing to messenger_pairing_and_syncing
---------
Co-authored-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2024-07-30 09:14:05 +00:00
|
|
|
return response.toJSON(err)
|
2023-06-01 05:33:57 +00:00
|
|
|
}
|
|
|
|
|
feat: fallback pairing seed (#5614)
* feat(pairing)!: Add extra parameters and remove v2 compatibility
This commit includes the following changes:
I have added a flag to maintain 2.29 compatibility.
Breaking change in connection string
The local pairing code that was parsing the connection string had a few non-upgradable features:
It was strictly checking the number of parameters, throwing an error if the number was different. This made it impossible to add parameters to it without breaking.
It was strictly checking the version number. This made increasing the version number impossible as older client would just refuse to connect.
The code has been changed so that:
Two parameters have been added, installation-id and key-uid. Those are needed for the fallback flow.
I have also removed version from the payload, since it wasn't used.
This means that we don't support v1 anymore. V2 parsing is supported . Going forward there's a clear strategy on how to update the protocol (append parameters, don't change existing one).
https://www.youtube.com/watch?v=oyLBGkS5ICk Is a must watch video for understanding the strategy
Changed MessengerResponse to use internally a map of installations rather than an array (minor)
Just moving towards maps as arrays tend to lead to subtle bugs.
Moved pairing methods to messenger_pairing.go
Just moved some methods
Added 2 new methods for the fallback flow
FinishPairingThroughSeedPhraseProcess
https://github.com/status-im/status-go/pull/5567/files#diff-1ad620b07fa3bd5fbc96c9f459d88829938a162bf1aaf41c61dea6e38b488d54R29
EnableAndSyncInstallation
https://github.com/status-im/status-go/pull/5567/files#diff-1ad620b07fa3bd5fbc96c9f459d88829938a162bf1aaf41c61dea6e38b488d54R18
Flow for clients
Client A1 is logged in
Client A2 is logged out
Client A1 shows a QR code
Client A2 scans a QR code
If connection fails on A2, the user will be prompted to enter a seed phrase.
If the generated account matches the key-uid from the QR code, A2 should call FinishPairingThroughSeedPhraseProcess with the installation id passed in the QR code. This will send installation information over waku. The user should be shown its own installation id and prompted to check the other device.
Client A1 will receive new installation data through waku, if they are still on the qr code page, they should show a popup to the user showing the received installation id, and a way to Enable and Sync, which should call the EnableAndSyncInstallation endpoint. This should finish the fallback syncing flow.
Current issues
Currently I haven't tested that all the data is synced after finishing the flow. I see that the two devices are paired correctly, but for example the DisplayName is not changed on the receiving device. I haven't had time to look into it further.
* test_: add more test for connection string parser
* fix_: fix panic when parse old connection string
* test_: add comments for TestMessengerPairAfterSeedPhrase
* fix_: correct error description
* feat_:rename FinishPairingThroughSeedPhraseProcess to EnableInstallationAndPair
* fix_: delete leftover
* fix_: add UniqueKey method
* fix_: unify the response for InputConnectionStringForBootstrapping
* fix_: remove fields installationID and keyUID in GethStatusBackend
* fix_: rename messenger_pairing to messenger_pairing_and_syncing
---------
Co-authored-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2024-07-30 09:14:05 +00:00
|
|
|
return response.toJSON(statusBackend.Logout())
|
2023-03-23 11:44:15 +00:00
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func InputConnectionStringForBootstrappingAnotherDevice(cs, configJSON string) string {
|
|
|
|
return logAndCallString(inputConnectionStringForBootstrappingAnotherDevice, cs, configJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
// inputConnectionStringForBootstrappingAnotherDevice starts a pairing.SendingClient
|
2023-03-23 11:44:15 +00:00
|
|
|
// The given server.ConnectionParams string will determine the server.Mode
|
|
|
|
//
|
|
|
|
// server.Mode = server.Receiving
|
|
|
|
// Used when the device is Logged in and therefore has Account keys and the has a camera to read a QR code
|
|
|
|
//
|
|
|
|
// Example: A mobile (device with camera) sending account data to a desktop device (device without camera)
|
2024-09-13 15:08:20 +00:00
|
|
|
func inputConnectionStringForBootstrappingAnotherDevice(cs, configJSON string) string {
|
2023-07-12 22:29:38 +00:00
|
|
|
var err error
|
2023-03-23 11:44:15 +00:00
|
|
|
if configJSON == "" {
|
|
|
|
return makeJSONResponse(fmt.Errorf("no config given, SenderClientConfig is expected"))
|
2022-08-31 12:47:16 +00:00
|
|
|
}
|
2022-08-31 11:44:12 +00:00
|
|
|
|
2023-07-12 22:29:38 +00:00
|
|
|
err = statusBackend.LocalPairingStateManager.StartPairing(cs)
|
|
|
|
defer func() { statusBackend.LocalPairingStateManager.StopPairing(cs, err) }()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2023-06-01 05:33:57 +00:00
|
|
|
|
2023-07-12 22:29:38 +00:00
|
|
|
err = pairing.StartUpSendingClient(statusBackend, cs, configJSON)
|
2022-08-31 14:01:45 +00:00
|
|
|
return makeJSONResponse(err)
|
2022-08-31 11:44:12 +00:00
|
|
|
}
|
2022-08-24 12:42:41 +00:00
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func GetConnectionStringForExportingKeypairsKeystores(configJSON string) string {
|
|
|
|
return logAndCallString(getConnectionStringForExportingKeypairsKeystores, configJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
// getConnectionStringForExportingKeypairsKeystores starts a pairing.SenderServer
|
2023-08-18 08:51:16 +00:00
|
|
|
// then generates a pairing.ConnectionParams. Used when the device is Logged in and therefore has Account keys
|
|
|
|
// and the device might not have a camera, to transfer kestore files of provided key uids.
|
2024-09-13 15:08:20 +00:00
|
|
|
func getConnectionStringForExportingKeypairsKeystores(configJSON string) string {
|
2023-08-18 08:51:16 +00:00
|
|
|
if configJSON == "" {
|
|
|
|
return makeJSONResponse(fmt.Errorf("no config given, SendingServerConfig is expected"))
|
|
|
|
}
|
|
|
|
|
|
|
|
cs, err := pairing.StartUpKeystoreFilesSenderServer(statusBackend, configJSON)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return cs
|
|
|
|
}
|
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
func InputConnectionStringForImportingKeypairsKeystores(cs, configJSON string) string {
|
|
|
|
return logAndCallString(inputConnectionStringForImportingKeypairsKeystores, cs, configJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
// inputConnectionStringForImportingKeypairsKeystores starts a pairing.ReceiverClient
|
2023-08-18 08:51:16 +00:00
|
|
|
// The given server.ConnectionParams string will determine the server.Mode
|
|
|
|
// Used when the device is Logged in and has Account keys and has a camera to read a QR code
|
|
|
|
//
|
|
|
|
// Example: A mobile device (device with a camera) receiving account data from
|
|
|
|
// a device with a screen (mobile or desktop devices)
|
2024-09-13 15:08:20 +00:00
|
|
|
func inputConnectionStringForImportingKeypairsKeystores(cs, configJSON string) string {
|
2023-08-18 08:51:16 +00:00
|
|
|
if configJSON == "" {
|
|
|
|
return makeJSONResponse(fmt.Errorf("no config given, ReceiverClientConfig is expected"))
|
|
|
|
}
|
|
|
|
|
|
|
|
err := pairing.StartUpKeystoreFilesReceivingClient(statusBackend, cs, configJSON)
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2023-02-15 14:42:12 +00:00
|
|
|
func ValidateConnectionString(cs string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(validateConnectionString, cs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateConnectionString(cs string) string {
|
2023-02-15 14:42:12 +00:00
|
|
|
err := pairing.ValidateConnectionString(cs)
|
|
|
|
if err == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return err.Error()
|
|
|
|
}
|
|
|
|
|
2022-08-24 12:42:41 +00:00
|
|
|
func EncodeTransfer(to string, value string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(encodeTransfer, to, value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func encodeTransfer(to string, value string) string {
|
2022-08-24 12:42:41 +00:00
|
|
|
result, err := abi_spec.EncodeTransfer(to, value)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to encode transfer", "to", to, "value", value, "error", err)
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func EncodeFunctionCall(method string, paramsJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(encodeFunctionCall, method, paramsJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
func encodeFunctionCall(method string, paramsJSON string) string {
|
2022-08-24 12:42:41 +00:00
|
|
|
result, err := abi_spec.Encode(method, paramsJSON)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to encode function call", "method", method, "paramsJSON", paramsJSON, "error", err)
|
2024-09-13 15:08:20 +00:00
|
|
|
return ""
|
2022-08-24 12:42:41 +00:00
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func DecodeParameters(decodeParamJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return decodeParameters(decodeParamJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeParameters(decodeParamJSON string) string {
|
2022-08-24 12:42:41 +00:00
|
|
|
decodeParam := struct {
|
|
|
|
BytesString string `json:"bytesString"`
|
|
|
|
Types []string `json:"types"`
|
|
|
|
}{}
|
|
|
|
err := json.Unmarshal([]byte(decodeParamJSON), &decodeParam)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to unmarshal json when decoding parameters", "decodeParamJSON", decodeParamJSON, "error", err)
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
result, err := abi_spec.Decode(decodeParam.BytesString, decodeParam.Types)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to decode parameters", "decodeParamJSON", decodeParamJSON, "error", err)
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
bytes, err := json.Marshal(result)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to marshal result", "result", result, "decodeParamJSON", decodeParamJSON, "error", err)
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return string(bytes)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HexToNumber(hex string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(hexToNumber, hex)
|
|
|
|
}
|
|
|
|
|
|
|
|
func hexToNumber(hex string) string {
|
2022-08-24 12:42:41 +00:00
|
|
|
return abi_spec.HexToNumber(hex)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NumberToHex(numString string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(numberToHex, numString)
|
|
|
|
}
|
|
|
|
|
|
|
|
func numberToHex(numString string) string {
|
2022-08-24 12:42:41 +00:00
|
|
|
return abi_spec.NumberToHex(numString)
|
|
|
|
}
|
2022-10-18 13:36:54 +00:00
|
|
|
|
|
|
|
func Sha3(str string) string {
|
|
|
|
return "0x" + abi_spec.Sha3(str)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Utf8ToHex(str string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(utf8ToHex, str)
|
|
|
|
}
|
|
|
|
|
|
|
|
func utf8ToHex(str string) string {
|
2022-10-18 13:36:54 +00:00
|
|
|
hexString, err := abi_spec.Utf8ToHex(str)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to convert utf8 to hex", "str", str, "error", err)
|
|
|
|
}
|
|
|
|
return hexString
|
|
|
|
}
|
|
|
|
|
|
|
|
func HexToUtf8(hexString string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(hexToUtf8, hexString)
|
|
|
|
}
|
|
|
|
|
|
|
|
func hexToUtf8(hexString string) string {
|
2022-10-18 13:36:54 +00:00
|
|
|
str, err := abi_spec.HexToUtf8(hexString)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to convert hex to utf8", "hexString", hexString, "error", err)
|
|
|
|
}
|
|
|
|
return str
|
|
|
|
}
|
|
|
|
|
|
|
|
func CheckAddressChecksum(address string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(checkAddressChecksum, address)
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkAddressChecksum(address string) string {
|
2022-10-18 13:36:54 +00:00
|
|
|
valid, err := abi_spec.CheckAddressChecksum(address)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to invoke check address checksum", "address", address, "error", err)
|
|
|
|
}
|
|
|
|
result, _ := json.Marshal(valid)
|
|
|
|
return string(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
func IsAddress(address string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(isAddress, address)
|
|
|
|
}
|
|
|
|
|
|
|
|
func isAddress(address string) string {
|
2022-10-18 13:36:54 +00:00
|
|
|
valid, err := abi_spec.IsAddress(address)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to invoke IsAddress", "address", address, "error", err)
|
|
|
|
}
|
|
|
|
result, _ := json.Marshal(valid)
|
|
|
|
return string(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
func ToChecksumAddress(address string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(toChecksumAddress, address)
|
|
|
|
}
|
|
|
|
|
|
|
|
func toChecksumAddress(address string) string {
|
2022-10-18 13:36:54 +00:00
|
|
|
address, err := abi_spec.ToChecksumAddress(address)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("failed to convert to checksum address", "address", address, "error", err)
|
|
|
|
}
|
|
|
|
return address
|
|
|
|
}
|
2023-01-04 01:55:07 +00:00
|
|
|
|
|
|
|
func DeserializeAndCompressKey(DesktopKey string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(deserializeAndCompressKey, DesktopKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
func deserializeAndCompressKey(DesktopKey string) string {
|
2023-01-04 01:55:07 +00:00
|
|
|
deserialisedKey := MultiformatDeserializePublicKey(DesktopKey, "f")
|
|
|
|
sanitisedKey := "0x" + deserialisedKey[5:]
|
|
|
|
return CompressPublicKey(sanitisedKey)
|
|
|
|
}
|
2023-06-21 13:04:43 +00:00
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
type InitLoggingRequest struct {
|
|
|
|
logutils.LogSettings
|
|
|
|
LogRequestGo bool `json:"LogRequestGo"`
|
|
|
|
LogRequestFile string `json:"LogRequestFile"`
|
|
|
|
}
|
|
|
|
|
2024-08-07 11:52:06 +00:00
|
|
|
// InitLogging The InitLogging function should be called when the application starts.
|
|
|
|
// This ensures that we can capture logs before the user login. Subsequent calls will update the logger settings.
|
2023-06-21 13:04:43 +00:00
|
|
|
// Before this, we can only capture logs after user login since we will only configure the logging after the login process.
|
|
|
|
func InitLogging(logSettingsJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
var logSettings InitLoggingRequest
|
2023-06-21 13:04:43 +00:00
|
|
|
var err error
|
|
|
|
if err = json.Unmarshal([]byte(logSettingsJSON), &logSettings); err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2024-08-07 13:07:26 +00:00
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
if err = logutils.OverrideRootLogWithConfig(logSettings.LogSettings, false); err == nil {
|
2024-08-07 11:52:06 +00:00
|
|
|
log.Info("logging initialised", "logSettings", logSettingsJSON)
|
|
|
|
}
|
2023-06-21 13:04:43 +00:00
|
|
|
|
2024-09-13 15:08:20 +00:00
|
|
|
if logSettings.LogRequestGo {
|
|
|
|
err = requestlog.ConfigureAndEnableRequestLogging(logSettings.LogRequestFile)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-21 13:04:43 +00:00
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
2024-02-19 12:53:01 +00:00
|
|
|
|
|
|
|
func GetRandomMnemonic() string {
|
|
|
|
mnemonic, err := account.GetRandomMnemonic()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return mnemonic
|
|
|
|
}
|
2024-07-03 11:51:14 +00:00
|
|
|
|
|
|
|
func ToggleCentralizedMetrics(requestJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(toggleCentralizedMetrics, requestJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
func toggleCentralizedMetrics(requestJSON string) string {
|
2024-07-03 11:51:14 +00:00
|
|
|
var request requests.ToggleCentralizedMetrics
|
|
|
|
err := json.Unmarshal([]byte(requestJSON), &request)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = request.Validate()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = statusBackend.ToggleCentralizedMetrics(request.Enabled)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
2024-07-19 12:22:15 +00:00
|
|
|
return makeJSONResponse(nil)
|
2024-07-03 11:51:14 +00:00
|
|
|
}
|
|
|
|
|
2024-07-11 07:39:19 +00:00
|
|
|
func CentralizedMetricsInfo() string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(centralizedMetricsInfo)
|
|
|
|
}
|
|
|
|
|
|
|
|
func centralizedMetricsInfo() string {
|
2024-07-11 07:39:19 +00:00
|
|
|
metricsInfo, err := statusBackend.CentralizedMetricsInfo()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
data, err := json.Marshal(metricsInfo)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
return string(data)
|
|
|
|
}
|
|
|
|
|
2024-07-03 11:51:14 +00:00
|
|
|
func AddCentralizedMetric(requestJSON string) string {
|
2024-09-13 15:08:20 +00:00
|
|
|
return logAndCallString(addCentralizedMetric, requestJSON)
|
|
|
|
}
|
|
|
|
|
|
|
|
func addCentralizedMetric(requestJSON string) string {
|
2024-07-03 11:51:14 +00:00
|
|
|
var request requests.AddCentralizedMetric
|
|
|
|
err := json.Unmarshal([]byte(requestJSON), &request)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = request.Validate()
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
metric := request.Metric
|
|
|
|
|
|
|
|
metric.EnsureID()
|
|
|
|
err = statusBackend.AddCentralizedMetric(*metric)
|
|
|
|
if err != nil {
|
|
|
|
return makeJSONResponse(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return metric.ID
|
|
|
|
}
|