diff --git a/Makefile b/Makefile index 4ba30e620..a83de954a 100644 --- a/Makefile +++ b/Makefile @@ -152,9 +152,10 @@ status-backend: ##@build Build status-backend to run status-go as HTTP server status-backend: build/bin/status-backend run-status-backend: PORT ?= 0 +MEDIA_HTTPS ?= true run-status-backend: generate run-status-backend: ##@run Start status-backend server listening to localhost:PORT - go run ./cmd/status-backend --address localhost:${PORT} + go run ./cmd/status-backend --address localhost:${PORT} --media-https=${MEDIA_HTTPS} statusgo-cross: statusgo-android statusgo-ios @echo "Full cross compilation done." diff --git a/api/app_state.go b/api/app_state.go index 7807b7705..96c505f9c 100644 --- a/api/app_state.go +++ b/api/app_state.go @@ -5,30 +5,39 @@ import ( "strings" ) -// appState represents if the app is in foreground, background or some other state -type appState string +// AppState represents if the app is in foreground, background or some other state +type AppState string -func (a appState) String() string { +func (a AppState) String() string { return string(a) } // Specific app states // see https://facebook.github.io/react-native/docs/appstate.html const ( - appStateForeground = appState("active") // these constant values are kept in sync with React Native - appStateBackground = appState("background") - appStateInactive = appState("inactive") + AppStateForeground = AppState("active") // these constant values are kept in sync with React Native + AppStateBackground = AppState("background") + AppStateInactive = AppState("inactive") - appStateInvalid = appState("") + AppStateInvalid = AppState("") ) // validAppStates returns an immutable set of valid states. -func validAppStates() []appState { - return []appState{appStateInactive, appStateBackground, appStateForeground} +func validAppStates() []AppState { + return []AppState{AppStateInactive, AppStateBackground, AppStateForeground} } -// parseAppState creates AppState from a string -func parseAppState(stateString string) (appState, error) { +func (a AppState) IsValid() bool { + for _, state := range validAppStates() { + if a == state { + return true + } + } + return false +} + +// ParseAppState creates AppState from a string +func ParseAppState(stateString string) (AppState, error) { // a bit of cleaning up stateString = strings.ToLower(strings.TrimSpace(stateString)) @@ -38,5 +47,5 @@ func parseAppState(stateString string) (appState, error) { } } - return appStateInvalid, fmt.Errorf("could not parse app state: %s", stateString) + return AppStateInvalid, fmt.Errorf("could not parse app state: %s", stateString) } diff --git a/api/app_state_test.go b/api/app_state_test.go index 307189390..37428ce38 100644 --- a/api/app_state_test.go +++ b/api/app_state_test.go @@ -7,22 +7,22 @@ import ( ) func TestParseAppType(t *testing.T) { - check := func(input string, expectedState appState, expectError bool) { - actualState, err := parseAppState(input) + check := func(input string, expectedState AppState, expectError bool) { + actualState, err := ParseAppState(input) assert.Equalf(t, expectedState, actualState, "unexpected result from parseAppState") if expectError { assert.NotNil(t, err, "error should not be nil") } } - check("active", appStateForeground, false) - check("background", appStateBackground, false) - check("inactive", appStateInactive, false) - check(" acTIVE ", appStateForeground, false) - check(" backGROUND ", appStateBackground, false) - check(" INACTIVE ", appStateInactive, false) - check("", appStateInvalid, true) - check("back ground", appStateInvalid, true) - check(" back ground ", appStateInvalid, true) - check(" ", appStateInvalid, true) + check("active", AppStateForeground, false) + check("background", AppStateBackground, false) + check("inactive", AppStateInactive, false) + check(" acTIVE ", AppStateForeground, false) + check(" backGROUND ", AppStateBackground, false) + check(" INACTIVE ", AppStateInactive, false) + check("", AppStateInvalid, true) + check("back ground", AppStateInvalid, true) + check(" back ground ", AppStateInvalid, true) + check(" ", AppStateInvalid, true) } diff --git a/api/backend.go b/api/backend.go index 1922feb73..f7dbeaf68 100644 --- a/api/backend.go +++ b/api/backend.go @@ -52,7 +52,7 @@ type StatusBackend interface { SignTypedDataV4(typed signercore.TypedData, address string, password string) (types.HexBytes, error) ConnectionChange(typ string, expensive bool) - AppStateChange(state string) + AppStateChange(state AppState) ExtractGroupMembershipSignatures(signaturePairs [][2]string) ([]string, error) SignGroupMembership(content string) (string, error) diff --git a/api/backend_test.go b/api/backend_test.go index 49f0f05f8..b2ca19a1e 100644 --- a/api/backend_test.go +++ b/api/backend_test.go @@ -396,28 +396,28 @@ func TestAppStateChange(t *testing.T) { var testCases = []struct { name string - fromState appState - toState appState - expectedState appState + fromState AppState + toState AppState + expectedState AppState }{ { name: "success", - fromState: appStateInactive, - toState: appStateBackground, - expectedState: appStateBackground, + fromState: AppStateInactive, + toState: AppStateBackground, + expectedState: AppStateBackground, }, { name: "invalid state", - fromState: appStateInactive, + fromState: AppStateInvalid, toState: "unexisting", - expectedState: appStateInactive, + expectedState: AppStateInvalid, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { backend.appState = tc.fromState - backend.AppStateChange(tc.toState.String()) + backend.AppStateChange(tc.toState) assert.Equal(t, tc.expectedState.String(), backend.appState.String()) }) } diff --git a/api/geth_backend.go b/api/geth_backend.go index 5e983d39f..02e621536 100644 --- a/api/geth_backend.go +++ b/api/geth_backend.go @@ -95,7 +95,7 @@ type GethStatusBackend struct { accountManager *account.GethManager transactor *transactions.Transactor connectionState connection.State - appState appState + appState AppState selectedAccountKeyID string allowAllRPC bool // used only for tests, disables api method restrictions LocalPairingStateManager *statecontrol.ProcessStateManager @@ -1196,7 +1196,7 @@ func replaceDBFile(dbPath string, newDBPath string) (cleanup func(), err error) return } -func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Account, s settings.Settings, keycardUID string, password string, newPassword string) error { +func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Account, s settings.Settings, keycardUID string, oldPassword string, newPassword string) error { messenger := b.Messenger() if messenger == nil { return errors.New("cannot resolve messenger instance") @@ -1207,7 +1207,7 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Accoun return err } - err = b.ensureDBsOpened(account, password) + err = b.ensureDBsOpened(account, oldPassword) if err != nil { return err } @@ -1300,7 +1300,7 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Accoun return err } - err = b.ChangeDatabasePassword(account.KeyUID, password, newPassword) + err = b.ChangeDatabasePassword(account.KeyUID, oldPassword, newPassword) if err != nil { return err } @@ -2488,15 +2488,15 @@ func (b *GethStatusBackend) ConnectionChange(typ string, expensive bool) { // AppStateChange handles app state changes (background/foreground). // state values: see https://facebook.github.io/react-native/docs/appstate.html -func (b *GethStatusBackend) AppStateChange(state string) { - var messenger *protocol.Messenger - s, err := parseAppState(state) - if err != nil { - b.logger.Error("AppStateChange failed, ignoring", zap.Error(err)) +func (b *GethStatusBackend) AppStateChange(state AppState) { + if !state.IsValid() { + b.logger.Warn("invalid app state, not reporting app state change", zap.Any("state", state)) return } - b.appState = s + var messenger *protocol.Messenger + + b.appState = state if b.statusNode == nil { b.logger.Warn("statusNode nil, not reporting app state change") @@ -2516,7 +2516,7 @@ func (b *GethStatusBackend) AppStateChange(state string) { return } - if s == appStateForeground { + if state == AppStateForeground { messenger.ToForeground() } else { messenger.ToBackground() diff --git a/cmd/status-backend/main.go b/cmd/status-backend/main.go index 763b15c8f..e6ad00d6e 100644 --- a/cmd/status-backend/main.go +++ b/cmd/status-backend/main.go @@ -9,14 +9,16 @@ import ( "github.com/ethereum/go-ethereum/log" - "github.com/status-im/status-go/cmd/status-backend/server" + backendServer "github.com/status-im/status-go/cmd/status-backend/server" "github.com/status-im/status-go/internal/version" "github.com/status-im/status-go/logutils" + mediaServer "github.com/status-im/status-go/server" ) var ( - address = flag.String("address", "", "host:port to listen") - logger = log.New("package", "status-go/cmd/status-backend") + address = flag.String("address", "", "host:port to listen") + useMediaHTTPS = flag.Bool("media-https", true, "use HTTPS for media server (default: true)") + logger = log.New("package", "status-go/cmd/status-backend") ) func init() { @@ -34,7 +36,9 @@ func init() { func main() { flag.Parse() - srv := server.NewServer() + mediaServer.UseHTTP = !*useMediaHTTPS + + srv := backendServer.NewServer() srv.Setup() err := srv.Listen(*address) diff --git a/mobile/callog/status_request_log.go b/mobile/callog/status_request_log.go index ae2d5f789..8873360bb 100644 --- a/mobile/callog/status_request_log.go +++ b/mobile/callog/status_request_log.go @@ -15,6 +15,7 @@ import ( var sensitiveKeys = []string{ "password", + "newPassword", "mnemonic", "openseaAPIKey", "poktToken", diff --git a/mobile/requests/app_state_change.go b/mobile/requests/app_state_change.go new file mode 100644 index 000000000..ae134ab84 --- /dev/null +++ b/mobile/requests/app_state_change.go @@ -0,0 +1,39 @@ +package requests + +import ( + "github.com/status-im/status-go/api" + "github.com/status-im/status-go/logutils" + + "go.uber.org/zap" + "gopkg.in/go-playground/validator.v9" +) + +// AppStateChange represents a request to change the app state from mobile +type AppStateChange struct { + State api.AppState `json:"state" validate:"required,app_state"` +} + +var validate *validator.Validate + +func init() { + validate = validator.New() + err := validate.RegisterValidation("app_state", validateAppState) + if err != nil { + logutils.ZapLogger().Error("register app state validation failed", zap.Error(err)) + } +} + +func validateAppState(fl validator.FieldLevel) bool { + state := api.AppState(fl.Field().String()) + switch state { + case api.AppStateBackground, api.AppStateForeground, api.AppStateInactive: + return true + default: + return false + } +} + +// Validate checks if the request is valid +func (r *AppStateChange) Validate() error { + return validate.Struct(r) +} diff --git a/mobile/requests/app_state_change_test.go b/mobile/requests/app_state_change_test.go new file mode 100644 index 000000000..fa9860eb5 --- /dev/null +++ b/mobile/requests/app_state_change_test.go @@ -0,0 +1,35 @@ +package requests + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/status-im/status-go/api" +) + +func TestAppStateChange(t *testing.T) { + t.Run("Valid States", func(t *testing.T) { + testCases := []api.AppState{ + api.AppStateBackground, + api.AppStateForeground, + api.AppStateInactive, + } + + for _, state := range testCases { + req := AppStateChange{State: state} + err := req.Validate() + require.NoError(t, err, "validation should pass for state: %s", state) + } + }) + + t.Run("Invalid State", func(t *testing.T) { + invalidStates := []api.AppState{"invalid-state", api.AppStateInvalid} + + for _, state := range invalidStates { + req := AppStateChange{State: state} + err := req.Validate() + require.Error(t, err, "validation should fail for invalid state: %s", state) + } + }) +} diff --git a/mobile/requests/input_connection_string_for_bootstrapping.go b/mobile/requests/input_connection_string_for_bootstrapping.go new file mode 100644 index 000000000..454708850 --- /dev/null +++ b/mobile/requests/input_connection_string_for_bootstrapping.go @@ -0,0 +1,16 @@ +package requests + +import ( + "gopkg.in/go-playground/validator.v9" + + "github.com/status-im/status-go/server/pairing" +) + +type InputConnectionStringForBootstrapping struct { + ConnectionString string `json:"connectionString" validate:"required"` + ReceiverClientConfig *pairing.ReceiverClientConfig `json:"receiverClientConfig" validate:"required"` +} + +func (r *InputConnectionStringForBootstrapping) Validate() error { + return validator.New().Struct(r) +} diff --git a/mobile/requests/input_connection_string_for_bootstrapping_another_device.go b/mobile/requests/input_connection_string_for_bootstrapping_another_device.go new file mode 100644 index 000000000..ffc1c34f5 --- /dev/null +++ b/mobile/requests/input_connection_string_for_bootstrapping_another_device.go @@ -0,0 +1,16 @@ +package requests + +import ( + "gopkg.in/go-playground/validator.v9" + + "github.com/status-im/status-go/server/pairing" +) + +type InputConnectionStringForBootstrappingAnotherDevice struct { + ConnectionString string `json:"connectionString" validate:"required"` + SenderClientConfig *pairing.SenderClientConfig `json:"senderClientConfig" validate:"required"` +} + +func (r *InputConnectionStringForBootstrappingAnotherDevice) Validate() error { + return validator.New().Struct(r) +} diff --git a/mobile/requests/input_connection_string_for_bootstrapping_test.go b/mobile/requests/input_connection_string_for_bootstrapping_test.go new file mode 100644 index 000000000..7efbc3fc2 --- /dev/null +++ b/mobile/requests/input_connection_string_for_bootstrapping_test.go @@ -0,0 +1,38 @@ +package requests + +import ( + "testing" + + "github.com/stretchr/testify/require" + + protocolRequests "github.com/status-im/status-go/protocol/requests" + "github.com/status-im/status-go/server/pairing" +) + +func TestInputConnectionStringForBootstrapping_Validate(t *testing.T) { + t.Run("Valid input", func(t *testing.T) { + input := &InputConnectionStringForBootstrapping{ + ConnectionString: "some-connection-string", + ReceiverClientConfig: &pairing.ReceiverClientConfig{ + ReceiverConfig: &pairing.ReceiverConfig{ + CreateAccount: &protocolRequests.CreateAccount{}, + }, + }, + } + + err := input.Validate() + require.NoError(t, err) + }) + + t.Run("Missing ReceiverClientConfig", func(t *testing.T) { + input := &InputConnectionStringForBootstrapping{ + ConnectionString: "some-connection-string", + ReceiverClientConfig: nil, + } + + err := input.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "ReceiverClientConfig") + require.Contains(t, err.Error(), "required") + }) +} diff --git a/mobile/requests/input_connection_string_for_importing_keypairs_keystores.go b/mobile/requests/input_connection_string_for_importing_keypairs_keystores.go new file mode 100644 index 000000000..ec837f9ad --- /dev/null +++ b/mobile/requests/input_connection_string_for_importing_keypairs_keystores.go @@ -0,0 +1,16 @@ +package requests + +import ( + "gopkg.in/go-playground/validator.v9" + + "github.com/status-im/status-go/server/pairing" +) + +type InputConnectionStringForImportingKeypairsKeystores struct { + ConnectionString string `json:"connectionString" validate:"required"` + KeystoreFilesReceiverClientConfig *pairing.KeystoreFilesReceiverClientConfig `json:"keystoreFilesReceiverClientConfig" validate:"required"` +} + +func (r *InputConnectionStringForImportingKeypairsKeystores) Validate() error { + return validator.New().Struct(r) +} diff --git a/mobile/status.go b/mobile/status.go index 9eb942d7a..3b431d8dc 100644 --- a/mobile/status.go +++ b/mobile/status.go @@ -28,6 +28,7 @@ import ( "github.com/status-im/status-go/images" "github.com/status-im/status-go/logutils" "github.com/status-im/status-go/logutils/requestlog" + m_requests "github.com/status-im/status-go/mobile/requests" "github.com/status-im/status-go/multiaccounts" "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/multiaccounts/settings" @@ -282,8 +283,9 @@ func callPrivateRPC(inputJSON string) string { return resp } +// Deprecated: Use VerifyAccountPasswordV2 instead func VerifyAccountPassword(keyStoreDir, address, password string) string { - return callWithResponse(verifyAccountPassword, keyStoreDir, address, password) + return verifyAccountPassword(keyStoreDir, address, password) } // verifyAccountPassword verifies account password. @@ -292,6 +294,26 @@ func verifyAccountPassword(keyStoreDir, address, password string) string { return makeJSONResponse(err) } +func VerifyAccountPasswordV2(requestJSON string) string { + return callWithResponse(verifyAccountPasswordV2, requestJSON) +} + +func verifyAccountPasswordV2(requestJSON string) string { + var request requests.VerifyAccountPassword + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + + err = request.Validate() + if err != nil { + return makeJSONResponse(err) + } + + _, err = statusBackend.AccountManager().VerifyAccountPassword(request.KeyStoreDir, request.Address, request.Password) + return makeJSONResponse(err) +} + func VerifyDatabasePasswordV2(requestJSON string) string { return callWithResponse(verifyDatabasePasswordV2, requestJSON) } @@ -568,6 +590,7 @@ func SaveAccountAndLogin(accountData, password, settingsJSON, configJSON, subacc return makeJSONResponse(nil) } +// Deprecated: Use DeleteMultiaccountV2 instead func DeleteMultiaccount(keyUID, keyStoreDir string) string { return callWithResponse(deleteMultiaccount, keyUID, keyStoreDir) } @@ -578,6 +601,26 @@ func deleteMultiaccount(keyUID, keyStoreDir string) string { return makeJSONResponse(err) } +func DeleteMultiaccountV2(requestJSON string) string { + return callWithResponse(deleteMultiaccountV2, requestJSON) +} + +func deleteMultiaccountV2(requestJSON string) string { + var request requests.DeleteMultiaccount + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + + err = request.Validate() + if err != nil { + return makeJSONResponse(err) + } + + err = statusBackend.DeleteMultiaccount(request.KeyUID, request.KeyStoreDir) + return makeJSONResponse(err) +} + func DeleteImportedKeyV2(requestJSON string) string { return callWithResponse(deleteImportedKeyV2, requestJSON) } @@ -710,8 +753,6 @@ func signMessage(rpcParams string) string { // SignTypedData unmarshall data into TypedData, validate it and signs with selected account, // if password matches selected account. -// -// Deprecated: Use SignTypedDataV2 instead. func SignTypedData(data, address, password string) string { return signTypedData(data, address, password) } @@ -729,26 +770,6 @@ func signTypedData(data, address, password string) string { return prepareJSONResponse(result.String(), err) } -func SignTypedDataV2(requestJSON string) string { - return callWithResponse(signTypedDataV2, requestJSON) -} - -func signTypedDataV2(requestJSON string) string { - var request requests.SignTypedData - err := json.Unmarshal([]byte(requestJSON), &request) - if err != nil { - return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) - } - - err = request.Validate() - if err != nil { - return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) - } - - result, err := statusBackend.SignTypedData(request.TypedData, request.Address, request.Password) - return prepareJSONResponse(result.String(), err) -} - // HashTypedData unmarshalls data into TypedData, validates it and hashes it. // //export HashTypedData @@ -840,11 +861,13 @@ func sendTransactionWithChainID(chainID int, txArgsJSON, password string) string return prepareJSONResponseWithCode(hash.String(), err, code) } +// Deprecated: Use SendTransactionV2 instead. func SendTransaction(txArgsJSON, password string) string { return sendTransaction(txArgsJSON, password) } // sendTransaction converts RPC args and calls backend.SendTransaction. +// Deprecated: Use sendTransactionV2 instead. func sendTransaction(txArgsJSON, password string) string { var params transactions.SendTxArgs err := json.Unmarshal([]byte(txArgsJSON), ¶ms) @@ -859,6 +882,29 @@ func sendTransaction(txArgsJSON, password string) string { return prepareJSONResponseWithCode(hash.String(), err, code) } +func SendTransactionV2(requestJSON string) string { + return callWithResponse(sendTransactionV2, requestJSON) +} + +func sendTransactionV2(requestJSON string) string { + var request requests.SendTransaction + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) + } + + err = request.Validate() + if err != nil { + return prepareJSONResponseWithCode(nil, err, codeFailedParseParams) + } + hash, err := statusBackend.SendTransaction(request.TxArgs, request.Password) + code := codeUnknown + if c, ok := errToCodeMap[err]; ok { + code = c + } + return prepareJSONResponseWithCode(hash.String(), err, code) +} + func SendTransactionWithSignature(txArgsJSON, sigString string) string { return callWithResponse(sendTransactionWithSignature, txArgsJSON, sigString) } @@ -987,6 +1033,7 @@ func addPeer(enode string) string { return makeJSONResponse(err) } +// Deprecated: Use ConnectionChangeV2 instead. func ConnectionChange(typ string, expensive int) { call(connectionChange, typ, expensive) } @@ -997,13 +1044,51 @@ func connectionChange(typ string, expensive int) { statusBackend.ConnectionChange(typ, expensive == 1) } +func ConnectionChangeV2(requestJSON string) string { + return callWithResponse(connectionChangeV2, requestJSON) +} + +func connectionChangeV2(requestJSON string) string { + var request requests.ConnectionChange + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + statusBackend.ConnectionChange(request.Type, request.Expensive) + return makeJSONResponse(nil) +} + +// Deprecated: Use AppStateChangeV2 instead. func AppStateChange(state string) { call(appStateChange, state) } // appStateChange handles app state changes (background/foreground). func appStateChange(state string) { - statusBackend.AppStateChange(state) + s, err := api.ParseAppState(state) + if err != nil { + logutils.ZapLogger().Error("parse app state failed, ignoring", zap.Error(err)) + return + } + statusBackend.AppStateChange(s) +} + +func AppStateChangeV2(requestJSON string) string { + return callWithResponse(appStateChangeV2, requestJSON) +} + +func appStateChangeV2(requestJSON string) string { + var request m_requests.AppStateChange + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + err = request.Validate() + if err != nil { + return makeJSONResponse(err) + } + statusBackend.AppStateChange(request.State) + return makeJSONResponse(nil) } func StartLocalNotifications() string { @@ -1137,6 +1222,7 @@ func colorID(pk string) string { return prepareJSONResponse(identityUtils.ToColorID(pk)) } +// Deprecated: Use ValidateMnemonicV2 instead. func ValidateMnemonic(mnemonic string) string { return validateMnemonic(mnemonic) } @@ -1161,6 +1247,19 @@ func validateMnemonic(mnemonic string) string { return string(data) } +func ValidateMnemonicV2(requestJSON string) string { + return callWithResponse(validateMnemonicV2, requestJSON) +} + +func validateMnemonicV2(requestJSON string) string { + var request requests.ValidateMnemonic + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + return validateMnemonic(request.Mnemonic) +} + func DecompressPublicKey(key string) string { return callWithResponse(decompressPublicKey, key) } @@ -1222,6 +1321,7 @@ func multiformatSerializePublicKey(key, outBase string) string { return cpk } +// Deprecated: Use MultiformatDeserializePublicKeyV2 instead. func MultiformatDeserializePublicKey(key, outBase string) string { return callWithResponse(multiformatDeserializePublicKey, key, outBase) } @@ -1236,6 +1336,20 @@ func multiformatDeserializePublicKey(key, outBase string) string { return pk } +func MultiformatDeserializePublicKeyV2(requestJSON string) string { + return callWithResponse(multiformatDeserializePublicKeyV2, requestJSON) +} + +func multiformatDeserializePublicKeyV2(requestJSON string) string { + var request requests.MultiformatDeserializePublicKey + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + return multiformatDeserializePublicKey(request.Key, request.OutBase) +} + +// Deprecated: Use ExportUnencryptedDatabaseV2 instead. func ExportUnencryptedDatabase(accountData, password, databasePath string) string { return exportUnencryptedDatabase(accountData, password, databasePath) } @@ -1251,6 +1365,21 @@ func exportUnencryptedDatabase(accountData, password, databasePath string) strin return makeJSONResponse(err) } +func ExportUnencryptedDatabaseV2(requestJSON string) string { + return callWithResponse(exportUnencryptedDatabaseV2, requestJSON) +} + +func exportUnencryptedDatabaseV2(requestJSON string) string { + var request requests.ExportUnencryptedDatabase + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + err = statusBackend.ExportUnencryptedDatabase(request.Account, request.Password, request.DatabasePath) + return makeJSONResponse(err) +} + +// Deprecated: Use ImportUnencryptedDatabaseV2 instead. func ImportUnencryptedDatabase(accountData, password, databasePath string) string { return importUnencryptedDatabase(accountData, password, databasePath) } @@ -1266,6 +1395,21 @@ func importUnencryptedDatabase(accountData, password, databasePath string) strin return makeJSONResponse(err) } +func ImportUnencryptedDatabaseV2(requestJSON string) string { + return callWithResponse(importUnencryptedDatabaseV2, requestJSON) +} + +func importUnencryptedDatabaseV2(requestJSON string) string { + var request requests.ImportUnencryptedDatabase + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + err = statusBackend.ImportUnencryptedDatabase(request.Account, request.Password, request.DatabasePath) + return makeJSONResponse(err) +} + +// Deprecated: Use ChangeDatabasePasswordV2 instead. func ChangeDatabasePassword(keyUID, password, newPassword string) string { return changeDatabasePassword(keyUID, password, newPassword) } @@ -1276,6 +1420,20 @@ func changeDatabasePassword(keyUID, password, newPassword string) string { return makeJSONResponse(err) } +func ChangeDatabasePasswordV2(requestJSON string) string { + return callWithResponse(changeDatabasePasswordV2, requestJSON) +} + +func changeDatabasePasswordV2(requestJSON string) string { + var request requests.ChangeDatabasePassword + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + return changeDatabasePassword(request.KeyUID, request.OldPassword, request.NewPassword) +} + +// Deprecated: Use ConvertToKeycardAccountV2 instead. func ConvertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword string) string { return convertToKeycardAccount(accountData, settingsJSON, keycardUID, password, newPassword) } @@ -1297,6 +1455,21 @@ func convertToKeycardAccount(accountData, settingsJSON, keycardUID, password, ne return makeJSONResponse(err) } +func ConvertToKeycardAccountV2(requestJSON string) string { + return callWithResponse(convertToKeycardAccountV2, requestJSON) +} + +func convertToKeycardAccountV2(requestJSON string) string { + var request requests.ConvertToKeycardAccount + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + err = statusBackend.ConvertToKeycardAccount(request.Account, request.Settings, request.KeycardUID, request.OldPassword, request.NewPassword) + return makeJSONResponse(err) +} + +// Deprecated: Use ConvertToRegularAccountV2 instead. func ConvertToRegularAccount(mnemonic, currPassword, newPassword string) string { return convertToRegularAccount(mnemonic, currPassword, newPassword) } @@ -1307,6 +1480,19 @@ func convertToRegularAccount(mnemonic, currPassword, newPassword string) string return makeJSONResponse(err) } +func ConvertToRegularAccountV2(requestJSON string) string { + return callWithResponse(convertToRegularAccountV2, requestJSON) +} + +func convertToRegularAccountV2(requestJSON string) string { + var request requests.ConvertToRegularAccount + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + return convertToRegularAccount(request.Mnemonic, request.CurrPassword, request.NewPassword) +} + func ImageServerTLSCert() string { cert, err := server.PublicMediaTLSCert() if err != nil { @@ -1390,6 +1576,7 @@ func fleets() string { return string(data) } +// Deprecated: Use SwitchFleetV2 instead. func SwitchFleet(fleet string, configJSON string) string { return callWithResponse(switchFleet, fleet, configJSON) } @@ -1416,7 +1603,38 @@ func switchFleet(fleet string, configJSON string) string { return makeJSONResponse(err) } +func SwitchFleetV2(requestJSON string) string { + return callWithResponse(switchFleetV2, requestJSON) +} + +func switchFleetV2(requestJSON string) string { + var request requests.SwitchFleet + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + return switchFleet(request.Fleet, request.ConfigJSON) +} + +// Deprecated: Use GenerateImagesV2 instead. func GenerateImages(filepath string, aX, aY, bX, bY int) string { + return generateImages(filepath, aX, aY, bX, bY) +} + +func GenerateImagesV2(requestJSON string) string { + return callWithResponse(generateImagesV2, requestJSON) +} + +func generateImagesV2(requestJSON string) string { + var request requests.GenerateImages + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + return generateImages(request.Filepath, request.AX, request.AY, request.BX, request.BY) +} + +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) @@ -1533,6 +1751,7 @@ func (i *inputConnectionStringForBootstrappingResponse) toJSON(err error) string return string(j) } +// Deprecated: Use InputConnectionStringForBootstrappingV2 instead. func InputConnectionStringForBootstrapping(cs, configJSON string) string { return callWithResponse(inputConnectionStringForBootstrapping, cs, configJSON) } @@ -1568,7 +1787,13 @@ func inputConnectionStringForBootstrapping(cs, configJSON string) string { return response.toJSON(err) } - err = pairing.StartUpReceivingClient(statusBackend, cs, configJSON) + var conf pairing.ReceiverClientConfig + err = json.Unmarshal([]byte(configJSON), &conf) + if err != nil { + return response.toJSON(err) + } + + err = pairing.StartUpReceivingClient(statusBackend, cs, &conf) if err != nil { return response.toJSON(err) } @@ -1576,6 +1801,46 @@ func inputConnectionStringForBootstrapping(cs, configJSON string) string { return response.toJSON(statusBackend.Logout()) } +func InputConnectionStringForBootstrappingV2(requestJSON string) string { + return callWithResponse(inputConnectionStringForBootstrappingV2, requestJSON) +} + +func inputConnectionStringForBootstrappingV2(requestJSON string) string { + var request m_requests.InputConnectionStringForBootstrapping + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + if err := request.Validate(); err != nil { + return makeJSONResponse(err) + } + + params := &pairing.ConnectionParams{} + err = params.FromString(request.ConnectionString) + if err != nil { + response := &inputConnectionStringForBootstrappingResponse{} + return response.toJSON(fmt.Errorf("could not parse connection string")) + } + response := &inputConnectionStringForBootstrappingResponse{ + InstallationID: params.InstallationID(), + KeyUID: params.KeyUID(), + } + + err = statusBackend.LocalPairingStateManager.StartPairing(request.ConnectionString) + defer func() { statusBackend.LocalPairingStateManager.StopPairing(request.ConnectionString, err) }() + if err != nil { + return response.toJSON(err) + } + + err = pairing.StartUpReceivingClient(statusBackend, request.ConnectionString, request.ReceiverClientConfig) + if err != nil { + return response.toJSON(err) + } + + return response.toJSON(statusBackend.Logout()) +} + +// Deprecated: Use InputConnectionStringForBootstrappingAnotherDeviceV2 instead. func InputConnectionStringForBootstrappingAnotherDevice(cs, configJSON string) string { return callWithResponse(inputConnectionStringForBootstrappingAnotherDevice, cs, configJSON) } @@ -1598,8 +1863,37 @@ func inputConnectionStringForBootstrappingAnotherDevice(cs, configJSON string) s if err != nil { return makeJSONResponse(err) } + var conf pairing.SenderClientConfig + err = json.Unmarshal([]byte(configJSON), &conf) + if err != nil { + return makeJSONResponse(err) + } - err = pairing.StartUpSendingClient(statusBackend, cs, configJSON) + err = pairing.StartUpSendingClient(statusBackend, cs, &conf) + return makeJSONResponse(err) +} + +func InputConnectionStringForBootstrappingAnotherDeviceV2(requestJSON string) string { + return callWithResponse(inputConnectionStringForBootstrappingAnotherDeviceV2, requestJSON) +} + +func inputConnectionStringForBootstrappingAnotherDeviceV2(requestJSON string) string { + var request m_requests.InputConnectionStringForBootstrappingAnotherDevice + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + if err := request.Validate(); err != nil { + return makeJSONResponse(err) + } + + err = statusBackend.LocalPairingStateManager.StartPairing(request.ConnectionString) + defer func() { statusBackend.LocalPairingStateManager.StopPairing(request.ConnectionString, err) }() + if err != nil { + return makeJSONResponse(err) + } + + err = pairing.StartUpSendingClient(statusBackend, request.ConnectionString, request.SenderClientConfig) return makeJSONResponse(err) } @@ -1622,6 +1916,7 @@ func getConnectionStringForExportingKeypairsKeystores(configJSON string) string return cs } +// Deprecated: Use InputConnectionStringForImportingKeypairsKeystoresV2 instead. func InputConnectionStringForImportingKeypairsKeystores(cs, configJSON string) string { return callWithResponse(inputConnectionStringForImportingKeypairsKeystores, cs, configJSON) } @@ -1637,7 +1932,29 @@ func inputConnectionStringForImportingKeypairsKeystores(cs, configJSON string) s return makeJSONResponse(fmt.Errorf("no config given, ReceiverClientConfig is expected")) } - err := pairing.StartUpKeystoreFilesReceivingClient(statusBackend, cs, configJSON) + var conf pairing.KeystoreFilesReceiverClientConfig + err := json.Unmarshal([]byte(configJSON), &conf) + if err != nil { + return makeJSONResponse(err) + } + err = pairing.StartUpKeystoreFilesReceivingClient(statusBackend, cs, &conf) + return makeJSONResponse(err) +} + +func InputConnectionStringForImportingKeypairsKeystoresV2(requestJSON string) string { + return callWithResponse(inputConnectionStringForImportingKeypairsKeystoresV2, requestJSON) +} + +func inputConnectionStringForImportingKeypairsKeystoresV2(requestJSON string) string { + var request m_requests.InputConnectionStringForImportingKeypairsKeystores + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + if err := request.Validate(); err != nil { + return makeJSONResponse(err) + } + err = pairing.StartUpKeystoreFilesReceivingClient(statusBackend, request.ConnectionString, request.KeystoreFilesReceiverClientConfig) return makeJSONResponse(err) } @@ -1653,6 +1970,7 @@ func validateConnectionString(cs string) string { return err.Error() } +// Deprecated: Use EncodeTransferV2 instead. func EncodeTransfer(to string, value string) string { return callWithResponse(encodeTransfer, to, value) } @@ -1666,6 +1984,20 @@ func encodeTransfer(to string, value string) string { return result } +func EncodeTransferV2(requestJSON string) string { + return callWithResponse(encodeTransferV2, requestJSON) +} + +func encodeTransferV2(requestJSON string) string { + var request requests.EncodeTransfer + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + return encodeTransfer(request.To, request.Value) +} + +// Deprecated: Use EncodeFunctionCallV2 instead. func EncodeFunctionCall(method string, paramsJSON string) string { return callWithResponse(encodeFunctionCall, method, paramsJSON) } @@ -1679,6 +2011,19 @@ func encodeFunctionCall(method string, paramsJSON string) string { return result } +func EncodeFunctionCallV2(requestJSON string) string { + return callWithResponse(encodeFunctionCallV2, requestJSON) +} + +func encodeFunctionCallV2(requestJSON string) string { + var request requests.EncodeFunctionCall + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + return encodeFunctionCall(request.Method, request.ParamsJSON) +} + func DecodeParameters(decodeParamJSON string) string { return decodeParameters(decodeParamJSON) } diff --git a/protocol/requests/change_database_password.go b/protocol/requests/change_database_password.go new file mode 100644 index 000000000..710b08cf0 --- /dev/null +++ b/protocol/requests/change_database_password.go @@ -0,0 +1,7 @@ +package requests + +type ChangeDatabasePassword struct { + KeyUID string `json:"keyUID"` + OldPassword string `json:"oldPassword"` + NewPassword string `json:"newPassword"` +} diff --git a/protocol/requests/connection_change.go b/protocol/requests/connection_change.go new file mode 100644 index 000000000..5124c18c5 --- /dev/null +++ b/protocol/requests/connection_change.go @@ -0,0 +1,6 @@ +package requests + +type ConnectionChange struct { + Type string `json:"type"` + Expensive bool `json:"expensive"` +} diff --git a/protocol/requests/convert_to_keycard_account.go b/protocol/requests/convert_to_keycard_account.go new file mode 100644 index 000000000..889283525 --- /dev/null +++ b/protocol/requests/convert_to_keycard_account.go @@ -0,0 +1,14 @@ +package requests + +import ( + "github.com/status-im/status-go/multiaccounts" + "github.com/status-im/status-go/multiaccounts/settings" +) + +type ConvertToKeycardAccount struct { + Account multiaccounts.Account `json:"account"` + Settings settings.Settings `json:"settings"` + KeycardUID string `json:"keycardUID"` + OldPassword string `json:"oldPassword"` + NewPassword string `json:"newPassword"` +} diff --git a/protocol/requests/convert_to_regular_account.go b/protocol/requests/convert_to_regular_account.go new file mode 100644 index 000000000..b33cef8ae --- /dev/null +++ b/protocol/requests/convert_to_regular_account.go @@ -0,0 +1,7 @@ +package requests + +type ConvertToRegularAccount struct { + Mnemonic string `json:"mnemonic"` + CurrPassword string `json:"currPassword"` + NewPassword string `json:"newPassword"` +} diff --git a/protocol/requests/delete_multiaccount.go b/protocol/requests/delete_multiaccount.go new file mode 100644 index 000000000..c90dc990c --- /dev/null +++ b/protocol/requests/delete_multiaccount.go @@ -0,0 +1,19 @@ +package requests + +import ( + "gopkg.in/go-playground/validator.v9" +) + +// DeleteMultiaccount represents a request to delete a multiaccount. +type DeleteMultiaccount struct { + // KeyUID is the unique identifier for the key. + KeyUID string `json:"keyUID" validate:"required"` + + // KeyStoreDir is the directory where the keystore files are located. + KeyStoreDir string `json:"keyStoreDir" validate:"required"` +} + +// Validate checks the validity of the DeleteMultiaccount request. +func (v *DeleteMultiaccount) Validate() error { + return validator.New().Struct(v) +} diff --git a/protocol/requests/encode_function_call.go b/protocol/requests/encode_function_call.go new file mode 100644 index 000000000..1671e0ca4 --- /dev/null +++ b/protocol/requests/encode_function_call.go @@ -0,0 +1,6 @@ +package requests + +type EncodeFunctionCall struct { + Method string `json:"method"` + ParamsJSON string `json:"paramsJSON"` +} diff --git a/protocol/requests/encode_transfer.go b/protocol/requests/encode_transfer.go new file mode 100644 index 000000000..a5d9beaf6 --- /dev/null +++ b/protocol/requests/encode_transfer.go @@ -0,0 +1,6 @@ +package requests + +type EncodeTransfer struct { + To string `json:"to"` + Value string `json:"value"` +} diff --git a/protocol/requests/export_unencrypted_database.go b/protocol/requests/export_unencrypted_database.go new file mode 100644 index 000000000..0a3525509 --- /dev/null +++ b/protocol/requests/export_unencrypted_database.go @@ -0,0 +1,9 @@ +package requests + +import "github.com/status-im/status-go/multiaccounts" + +type ExportUnencryptedDatabase struct { + Account multiaccounts.Account `json:"account"` + Password string `json:"password"` + DatabasePath string `json:"databasePath"` +} diff --git a/protocol/requests/generate_images.go b/protocol/requests/generate_images.go new file mode 100644 index 000000000..3385ca734 --- /dev/null +++ b/protocol/requests/generate_images.go @@ -0,0 +1,9 @@ +package requests + +type GenerateImages struct { + Filepath string `json:"filepath"` + AX int `json:"aX"` + AY int `json:"aY"` + BX int `json:"bX"` + BY int `json:"bY"` +} diff --git a/protocol/requests/import_unencrypted_database.go b/protocol/requests/import_unencrypted_database.go new file mode 100644 index 000000000..46e93200a --- /dev/null +++ b/protocol/requests/import_unencrypted_database.go @@ -0,0 +1,9 @@ +package requests + +import "github.com/status-im/status-go/multiaccounts" + +type ImportUnencryptedDatabase struct { + Account multiaccounts.Account `json:"account"` + Password string `json:"password"` + DatabasePath string `json:"databasePath"` +} diff --git a/protocol/requests/input_connection_string_for_importing_keypairs_keystores.go b/protocol/requests/input_connection_string_for_importing_keypairs_keystores.go new file mode 100644 index 000000000..689c02b60 --- /dev/null +++ b/protocol/requests/input_connection_string_for_importing_keypairs_keystores.go @@ -0,0 +1,6 @@ +package requests + +type InputConnectionStringForImportingKeypairsKeystores struct { + ConnectionString string `json:"connectionString"` + ConfigJSON string `json:"configJSON"` +} diff --git a/protocol/requests/multiformat_deserialize_public_key.go b/protocol/requests/multiformat_deserialize_public_key.go new file mode 100644 index 000000000..0ee4df770 --- /dev/null +++ b/protocol/requests/multiformat_deserialize_public_key.go @@ -0,0 +1,6 @@ +package requests + +type MultiformatDeserializePublicKey struct { + Key string `json:"key"` + OutBase string `json:"outBase"` +} diff --git a/protocol/requests/send_transaction.go b/protocol/requests/send_transaction.go new file mode 100644 index 000000000..a28b3a166 --- /dev/null +++ b/protocol/requests/send_transaction.go @@ -0,0 +1,19 @@ +package requests + +import ( + "gopkg.in/go-playground/validator.v9" + + "github.com/status-im/status-go/transactions" +) + +// SendTransaction represents a request to send a transaction. +type SendTransaction struct { + TxArgs transactions.SendTxArgs `json:"txArgs"` + Password string `json:"password" validate:"required"` +} + +// Validate checks the fields of SendTransaction to ensure they meet the requirements. +func (st *SendTransaction) Validate() error { + validate := validator.New() + return validate.Struct(st) +} diff --git a/protocol/requests/switch_fleet.go b/protocol/requests/switch_fleet.go new file mode 100644 index 000000000..5d7d155d2 --- /dev/null +++ b/protocol/requests/switch_fleet.go @@ -0,0 +1,6 @@ +package requests + +type SwitchFleet struct { + Fleet string `json:"fleet"` + ConfigJSON string `json:"configJSON"` +} diff --git a/protocol/requests/validate_mnemonic.go b/protocol/requests/validate_mnemonic.go new file mode 100644 index 000000000..cb50e46bd --- /dev/null +++ b/protocol/requests/validate_mnemonic.go @@ -0,0 +1,5 @@ +package requests + +type ValidateMnemonic struct { + Mnemonic string `json:"mnemonic"` +} diff --git a/protocol/requests/verify_account_password.go b/protocol/requests/verify_account_password.go new file mode 100644 index 000000000..78b263461 --- /dev/null +++ b/protocol/requests/verify_account_password.go @@ -0,0 +1,22 @@ +package requests + +import ( + "gopkg.in/go-playground/validator.v9" +) + +// VerifyAccountPassword represents a request to verify an account password. +type VerifyAccountPassword struct { + // KeyStoreDir is the directory where the keystore files are located. + KeyStoreDir string `json:"keyStoreDir" validate:"required"` + + // Address is the Ethereum address for the account. + Address string `json:"address" validate:"required"` + + // Password is the password to verify against the keystore. + Password string `json:"password" validate:"required"` +} + +// Validate checks the validity of the VerifyAccountPassword request. +func (v *VerifyAccountPassword) Validate() error { + return validator.New().Struct(v) +} diff --git a/server/pairing/client.go b/server/pairing/client.go index 5fe207c87..f8fc7a392 100644 --- a/server/pairing/client.go +++ b/server/pairing/client.go @@ -4,7 +4,6 @@ import ( "bytes" "crypto/tls" "crypto/x509" - "encoding/json" "encoding/pem" "fmt" "io" @@ -311,18 +310,13 @@ func (c *SenderClient) receiveInstallationData() error { } // setupSendingClient creates a new SenderClient after parsing string inputs -func setupSendingClient(backend *api.GethStatusBackend, cs, configJSON string) (*SenderClient, error) { +func setupSendingClient(backend *api.GethStatusBackend, cs string, conf *SenderClientConfig) (*SenderClient, error) { ccp := new(ConnectionParams) err := ccp.FromString(cs) if err != nil { return nil, err } - conf := NewSenderClientConfig() - err = json.Unmarshal([]byte(configJSON), conf) - if err != nil { - return nil, err - } err = validateAndVerifyPassword(conf, conf.SenderConfig) if err != nil { return nil, err @@ -334,8 +328,8 @@ func setupSendingClient(backend *api.GethStatusBackend, cs, configJSON string) ( } // StartUpSendingClient creates a SenderClient and triggers all `send` calls in sequence to the ReceiverServer -func StartUpSendingClient(backend *api.GethStatusBackend, cs, configJSON string) error { - c, err := setupSendingClient(backend, cs, configJSON) +func StartUpSendingClient(backend *api.GethStatusBackend, cs string, conf *SenderClientConfig) error { + c, err := setupSendingClient(backend, cs, conf) if err != nil { return err } @@ -514,19 +508,13 @@ func (c *ReceiverClient) sendInstallationData() error { } // setupReceivingClient creates a new ReceiverClient after parsing string inputs -func setupReceivingClient(backend *api.GethStatusBackend, cs, configJSON string) (*ReceiverClient, error) { +func setupReceivingClient(backend *api.GethStatusBackend, cs string, conf *ReceiverClientConfig) (*ReceiverClient, error) { ccp := new(ConnectionParams) err := ccp.FromString(cs) if err != nil { return nil, err } - conf := NewReceiverClientConfig() - err = json.Unmarshal([]byte(configJSON), conf) - if err != nil { - return nil, err - } - // This is a temporal solution to allow clients not to pass DeviceType. // Check DeviceType deprecation reason for more info. conf.ReceiverConfig.DeviceType = runtime.GOOS @@ -548,8 +536,8 @@ func setupReceivingClient(backend *api.GethStatusBackend, cs, configJSON string) } // StartUpReceivingClient creates a ReceiverClient and triggers all `receive` calls in sequence to the SenderServer -func StartUpReceivingClient(backend *api.GethStatusBackend, cs, configJSON string) error { - c, err := setupReceivingClient(backend, cs, configJSON) +func StartUpReceivingClient(backend *api.GethStatusBackend, cs string, conf *ReceiverClientConfig) error { + c, err := setupReceivingClient(backend, cs, conf) if err != nil { return err } @@ -652,18 +640,13 @@ func (c *KeystoreFilesReceiverClient) receiveKeystoreFilesData() error { } // setupKeystoreFilesReceivingClient creates a new ReceiverClient after parsing string inputs -func setupKeystoreFilesReceivingClient(backend *api.GethStatusBackend, cs, configJSON string) (*KeystoreFilesReceiverClient, error) { +func setupKeystoreFilesReceivingClient(backend *api.GethStatusBackend, cs string, conf *KeystoreFilesReceiverClientConfig) (*KeystoreFilesReceiverClient, error) { ccp := new(ConnectionParams) err := ccp.FromString(cs) if err != nil { return nil, err } - conf := NewKeystoreFilesReceiverClientConfig() - err = json.Unmarshal([]byte(configJSON), conf) - if err != nil { - return nil, err - } err = validateKeystoreFilesConfig(backend, conf) if err != nil { return nil, err @@ -673,8 +656,8 @@ func setupKeystoreFilesReceivingClient(backend *api.GethStatusBackend, cs, confi } // StartUpKeystoreFilesReceivingClient creates a KeystoreFilesReceiverClient and triggers all `receive` calls in sequence to the KeystoreFilesSenderServer -func StartUpKeystoreFilesReceivingClient(backend *api.GethStatusBackend, cs, configJSON string) error { - c, err := setupKeystoreFilesReceivingClient(backend, cs, configJSON) +func StartUpKeystoreFilesReceivingClient(backend *api.GethStatusBackend, cs string, conf *KeystoreFilesReceiverClientConfig) error { + c, err := setupKeystoreFilesReceivingClient(backend, cs, conf) if err != nil { return err } diff --git a/server/pairing/sync_device_test.go b/server/pairing/sync_device_test.go index 14ce6bffd..02df4f1f6 100644 --- a/server/pairing/sync_device_test.go +++ b/server/pairing/sync_device_test.go @@ -155,10 +155,7 @@ func (s *SyncDeviceSuite) pairAccounts(serverBackend *api.GethStatusBackend, ser ClientConfig: new(ClientConfig), } - clientConfigBytes, err := json.Marshal(clientPayloadSourceConfig) - require.NoError(s.T(), err) - - err = StartUpReceivingClient(clientBackend, connectionString, string(clientConfigBytes)) + err = StartUpReceivingClient(clientBackend, connectionString, &clientPayloadSourceConfig) require.NoError(s.T(), err) require.True(s.T(), serverBackend.Messenger().HasPairedDevices()) @@ -279,18 +276,19 @@ func (s *SyncDeviceSuite) TestPairingSyncDeviceClientAsSender() { clientActiveAccount, err := clientBackend.GetActiveAccount() require.NoError(s.T(), err) clientKeystorePath := filepath.Join(clientTmpDir, api.DefaultKeystoreRelativePath, clientActiveAccount.KeyUID) - clientPayloadSourceConfig := SenderClientConfig{ - SenderConfig: &SenderConfig{ - KeystorePath: clientKeystorePath, - DeviceType: "android", - KeyUID: clientActiveAccount.KeyUID, - Password: s.password, - }, - ClientConfig: new(ClientConfig), + + makeNewSenderClientConfig := func() *SenderClientConfig { + return &SenderClientConfig{ + SenderConfig: &SenderConfig{ + KeystorePath: clientKeystorePath, + DeviceType: "android", + KeyUID: clientActiveAccount.KeyUID, + Password: s.password, + }, + ClientConfig: new(ClientConfig), + } } - clientConfigBytes, err := json.Marshal(clientPayloadSourceConfig) - require.NoError(s.T(), err) - err = StartUpSendingClient(clientBackend, cs, string(clientConfigBytes)) + err = StartUpSendingClient(clientBackend, cs, makeNewSenderClientConfig()) require.NoError(s.T(), err) // check that the server has the same data as the client @@ -339,7 +337,7 @@ func (s *SyncDeviceSuite) TestPairingSyncDeviceClientAsSender() { // repeat local pairing, we should expect no error after receiver logged in cs, err = StartUpReceiverServer(serverBackend, string(serverConfigBytes)) require.NoError(s.T(), err) - err = StartUpSendingClient(clientBackend, cs, string(clientConfigBytes)) + err = StartUpSendingClient(clientBackend, cs, makeNewSenderClientConfig()) require.NoError(s.T(), err) require.True(s.T(), clientMessenger.HasPairedDevices()) require.True(s.T(), serverMessenger.HasPairedDevices()) @@ -348,7 +346,7 @@ func (s *SyncDeviceSuite) TestPairingSyncDeviceClientAsSender() { require.NoError(s.T(), serverBackend.Logout()) cs, err = StartUpReceiverServer(serverBackend, string(serverConfigBytes)) require.NoError(s.T(), err) - err = StartUpSendingClient(clientBackend, cs, string(clientConfigBytes)) + err = StartUpSendingClient(clientBackend, cs, makeNewSenderClientConfig()) require.NoError(s.T(), err) } @@ -418,19 +416,19 @@ func (s *SyncDeviceSuite) TestPairingSyncDeviceClientAsReceiver() { err = clientBackend.OpenAccounts() require.NoError(s.T(), err) - clientPayloadSourceConfig := ReceiverClientConfig{ - ReceiverConfig: &ReceiverConfig{ - CreateAccount: &requests.CreateAccount{ - RootDataDir: clientTmpDir, - KdfIterations: expectedKDFIterations, - DeviceName: "device-1", + makeNewReceiverClientConfig := func() *ReceiverClientConfig { + return &ReceiverClientConfig{ + ReceiverConfig: &ReceiverConfig{ + CreateAccount: &requests.CreateAccount{ + RootDataDir: clientTmpDir, + KdfIterations: expectedKDFIterations, + DeviceName: "device-1", + }, }, - }, - ClientConfig: new(ClientConfig), + ClientConfig: new(ClientConfig), + } } - clientConfigBytes, err := json.Marshal(clientPayloadSourceConfig) - require.NoError(s.T(), err) - err = StartUpReceivingClient(clientBackend, cs, string(clientConfigBytes)) + err = StartUpReceivingClient(clientBackend, cs, makeNewReceiverClientConfig()) require.NoError(s.T(), err) // check that the client has the same data as the server @@ -478,7 +476,7 @@ func (s *SyncDeviceSuite) TestPairingSyncDeviceClientAsReceiver() { // repeat local pairing, we should expect no error after receiver logged in cs, err = StartUpSenderServer(serverBackend, string(configBytes)) require.NoError(s.T(), err) - err = StartUpReceivingClient(clientBackend, cs, string(clientConfigBytes)) + err = StartUpReceivingClient(clientBackend, cs, makeNewReceiverClientConfig()) require.NoError(s.T(), err) require.True(s.T(), serverMessenger.HasPairedDevices()) require.True(s.T(), clientMessenger.HasPairedDevices()) @@ -487,7 +485,7 @@ func (s *SyncDeviceSuite) TestPairingSyncDeviceClientAsReceiver() { require.NoError(s.T(), clientBackend.Logout()) cs, err = StartUpSenderServer(serverBackend, string(configBytes)) require.NoError(s.T(), err) - err = StartUpReceivingClient(clientBackend, cs, string(clientConfigBytes)) + err = StartUpReceivingClient(clientBackend, cs, makeNewReceiverClientConfig()) require.NoError(s.T(), err) } @@ -849,9 +847,7 @@ func (s *SyncDeviceSuite) TestTransferringKeystoreFiles() { }, ClientConfig: new(ClientConfig), } - clientConfigBytes, err := json.Marshal(clientPayloadSourceConfig) - require.NoError(s.T(), err) - err = StartUpKeystoreFilesReceivingClient(clientBackend, cs, string(clientConfigBytes)) + err = StartUpKeystoreFilesReceivingClient(clientBackend, cs, &clientPayloadSourceConfig) require.NoError(s.T(), err) // check client - client should contain keystore files for imported seed phrase @@ -1157,9 +1153,7 @@ func (s *SyncDeviceSuite) TestTransferringKeystoreFilesAfterStopUisngKeycard() { }, ClientConfig: new(ClientConfig), } - clientConfigBytes, err := json.Marshal(clientPayloadSourceConfig) - require.NoError(s.T(), err) - err = StartUpKeystoreFilesReceivingClient(clientBackend, cs, string(clientConfigBytes)) + err = StartUpKeystoreFilesReceivingClient(clientBackend, cs, &clientPayloadSourceConfig) require.NoError(s.T(), err) // Check server - server should contain keystore files for imported seed phrase @@ -1212,9 +1206,7 @@ func (s *SyncDeviceSuite) TestPreventLoggedInAccountLocalPairingClientAsReceiver }, ClientConfig: new(ClientConfig), } - clientConfigBytes, err := json.Marshal(clientPayloadSourceConfig) - s.NoError(err) - err = StartUpReceivingClient(clientBackend, cs, string(clientConfigBytes)) + err = StartUpReceivingClient(clientBackend, cs, &clientPayloadSourceConfig) s.ErrorIs(err, ErrLoggedInKeyUIDConflict) } @@ -1256,8 +1248,6 @@ func (s *SyncDeviceSuite) TestPreventLoggedInAccountLocalPairingClientAsSender() }, ClientConfig: new(ClientConfig), } - clientConfigBytes, err := json.Marshal(clientPayloadSourceConfig) - s.NoError(err) - err = StartUpSendingClient(clientBackend, cs, string(clientConfigBytes)) + err = StartUpSendingClient(clientBackend, cs, &clientPayloadSourceConfig) s.ErrorContains(err, "[client] status not ok when sending account data, received '500 Internal Server Error'") } diff --git a/server/server.go b/server/server.go index 70c2b0caa..03a0c4d54 100644 --- a/server/server.go +++ b/server/server.go @@ -57,10 +57,23 @@ func (s *Server) mustGetHost() string { func (s *Server) listenAndServe() { defer common.LogOnPanic() - cfg := &tls.Config{Certificates: []tls.Certificate{*s.cert}, ServerName: s.hostname, MinVersion: tls.VersionTLS12} - // in case of restart, we should use the same port as the first start in order not to break existing links - listener, err := tls.Listen("tcp", s.getHost(), cfg) + var listener net.Listener + var err error + + if s.cert != nil { + // HTTPS mode + cfg := &tls.Config{ + Certificates: []tls.Certificate{*s.cert}, + ServerName: s.hostname, + MinVersion: tls.VersionTLS12, + } + listener, err = tls.Listen("tcp", s.getHost(), cfg) + } else { + // HTTP mode + listener, err = net.Listen("tcp", s.getHost()) + } + if err != nil { s.logger.Error("failed to start server, retrying", zap.Error(err)) s.ResetPort() diff --git a/server/server_media.go b/server/server_media.go index 0af8c7647..8f5100f27 100644 --- a/server/server_media.go +++ b/server/server_media.go @@ -1,6 +1,7 @@ package server import ( + "crypto/tls" "database/sql" "net/url" "strconv" @@ -13,6 +14,14 @@ import ( "github.com/status-im/status-go/signal" ) +var ( + // UseHTTP controls whether the media server uses HTTP instead of HTTPS. + // Set to true to avoid TLS certificate issues with react-native-fast-image + // on Android, which has limitations with dynamic certificate updates. + // Pls check doc/use-status-backend-server.md in status-mobile for more details + UseHTTP = false +) + type MediaServer struct { Server @@ -24,14 +33,18 @@ type MediaServer struct { // NewMediaServer returns a *MediaServer func NewMediaServer(db *sql.DB, downloader *ipfs.Downloader, multiaccountsDB *multiaccounts.Database, walletDB *sql.DB) (*MediaServer, error) { - err := generateMediaTLSCert() - if err != nil { - return nil, err + var cert *tls.Certificate + if !UseHTTP { + err := generateMediaTLSCert() + if err != nil { + return nil, err + } + cert = globalMediaCertificate } s := &MediaServer{ Server: NewServer( - globalMediaCertificate, + cert, Localhost, signal.SendMediaServerStarted, logutils.ZapLogger().Named("MediaServer"), @@ -65,6 +78,13 @@ func NewMediaServer(db *sql.DB, downloader *ipfs.Downloader, multiaccountsDB *mu return s, nil } +func (s *MediaServer) MakeBaseURL() *url.URL { + return &url.URL{ + Scheme: map[bool]string{true: "http", false: "https"}[UseHTTP], + Host: s.mustGetHost(), + } +} + func (s *MediaServer) MakeImageServerURL() string { u := s.MakeBaseURL() u.Path = basePath + "/"