Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat_: use SensitiveString in WalletConfig #6192

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat/wallet-config-sensitive-string
  • Loading branch information
igor-sirotin committed Dec 11, 2024
commit 201afb96eee31a01ce1a3f76d93b5f1ec2962d67
26 changes: 16 additions & 10 deletions api/backend_test.go
Original file line number Diff line number Diff line change
@@ -43,6 +43,8 @@ import (
"github.com/status-im/status-go/t/helpers"
"github.com/status-im/status-go/t/utils"
"github.com/status-im/status-go/walletdatabase"
"github.com/status-im/status-go/internal/security"
"github.com/brianvoe/gofakeit/v6"
)

var (
@@ -1515,20 +1517,24 @@ func TestSetFleet(t *testing.T) {
require.NoError(t, b.Logout())
}

func fakeToken() security.SensitiveString {
return security.NewSensitiveString(gofakeit.LetterN(10))
}

func TestWalletConfigOnLoginAccount(t *testing.T) {
utils.Init()
password := "some-password2" // nolint: goconst
tmpdir := t.TempDir()
poktToken := "grove-token" // nolint: goconst
infuraToken := "infura-token" // nolint: goconst
alchemyEthereumMainnetToken := "alchemy-ethereum-mainnet-token"
alchemyEthereumSepoliaToken := "alchemy-ethereum-sepolia-token"
alchemyArbitrumMainnetToken := "alchemy-arbitrum-mainnet-token"
alchemyArbitrumSepoliaToken := "alchemy-arbitrum-sepolia-token"
alchemyOptimismMainnetToken := "alchemy-optimism-mainnet-token"
alchemyOptimismSepoliaToken := "alchemy-optimism-sepolia-token"
raribleMainnetAPIKey := "rarible-mainnet-api-key" // nolint: gosec
raribleTestnetAPIKey := "rarible-testnet-api-key" // nolint: gosec
poktToken := "grove-token" // nolint: goconst
infuraToken := fakeToken()
alchemyEthereumMainnetToken := fakeToken()
alchemyEthereumSepoliaToken := fakeToken()
alchemyArbitrumMainnetToken := fakeToken()
alchemyArbitrumSepoliaToken := fakeToken()
alchemyOptimismMainnetToken := fakeToken()
alchemyOptimismSepoliaToken := fakeToken()
raribleMainnetAPIKey := fakeToken()
raribleTestnetAPIKey := fakeToken()

b := NewGethStatusBackend(tt.MustCreateTestLogger())
createAccountRequest := &requests.CreateAccount{
2 changes: 1 addition & 1 deletion api/default_networks.go
Original file line number Diff line number Diff line change
@@ -186,7 +186,7 @@ func setRPCs(networks []params.Network, request *requests.WalletSecretsConfig) [
)

appendToken := func(url string) string {
if strings.Contains(url, infura) && request.InfuraToken != "" {
if strings.Contains(url, infura) && !request.InfuraToken.Empty() {
return url + request.InfuraToken
} else if strings.Contains(url, grove) && request.PoktToken != "" {
return url + request.PoktToken
33 changes: 17 additions & 16 deletions api/defaults.go
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ import (
"github.com/status-im/status-go/protocol/identity/alias"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/requests"
"github.com/status-im/status-go/internal/security"
)

const (
@@ -170,61 +171,61 @@ func SetFleet(fleet string, nodeConfig *params.NodeConfig) error {
func buildWalletConfig(request *requests.WalletSecretsConfig, statusProxyEnabled bool) params.WalletConfig {
walletConfig := params.WalletConfig{
Enabled: true,
AlchemyAPIKeys: make(map[uint64]string),
AlchemyAPIKeys: make(map[uint64]security.SensitiveString),
}

if request.StatusProxyStageName != "" {
walletConfig.StatusProxyStageName = request.StatusProxyStageName
}

if request.OpenseaAPIKey != "" {
if !request.OpenseaAPIKey.Empty() {
walletConfig.OpenseaAPIKey = request.OpenseaAPIKey
}

if request.RaribleMainnetAPIKey != "" {
if !request.RaribleMainnetAPIKey.Empty() {
walletConfig.RaribleMainnetAPIKey = request.RaribleMainnetAPIKey
}

if request.RaribleTestnetAPIKey != "" {
if !request.RaribleTestnetAPIKey.Empty() {
walletConfig.RaribleTestnetAPIKey = request.RaribleTestnetAPIKey
}

if request.InfuraToken != "" {
if !request.InfuraToken.Empty() {
walletConfig.InfuraAPIKey = request.InfuraToken
}

if request.InfuraSecret != "" {
if !request.InfuraSecret.Empty() {
walletConfig.InfuraAPIKeySecret = request.InfuraSecret
}

if request.AlchemyEthereumMainnetToken != "" {
if !request.AlchemyEthereumMainnetToken.Empty() {
walletConfig.AlchemyAPIKeys[mainnetChainID] = request.AlchemyEthereumMainnetToken
}
if request.AlchemyEthereumSepoliaToken != "" {
if !request.AlchemyEthereumSepoliaToken.Empty() {
walletConfig.AlchemyAPIKeys[sepoliaChainID] = request.AlchemyEthereumSepoliaToken
}
if request.AlchemyArbitrumMainnetToken != "" {
if !request.AlchemyArbitrumMainnetToken.Empty() {
walletConfig.AlchemyAPIKeys[arbitrumChainID] = request.AlchemyArbitrumMainnetToken
}
if request.AlchemyArbitrumSepoliaToken != "" {
if !request.AlchemyArbitrumSepoliaToken.Empty() {
walletConfig.AlchemyAPIKeys[arbitrumSepoliaChainID] = request.AlchemyArbitrumSepoliaToken
}
if request.AlchemyOptimismMainnetToken != "" {
if !request.AlchemyOptimismMainnetToken.Empty() {
walletConfig.AlchemyAPIKeys[optimismChainID] = request.AlchemyOptimismMainnetToken
}
if request.AlchemyOptimismSepoliaToken != "" {
if !request.AlchemyOptimismSepoliaToken.Empty() {
walletConfig.AlchemyAPIKeys[optimismSepoliaChainID] = request.AlchemyOptimismSepoliaToken
}
if request.StatusProxyMarketUser != "" {
if !request.StatusProxyMarketUser.Empty() {
walletConfig.StatusProxyMarketUser = request.StatusProxyMarketUser
}
if request.StatusProxyMarketPassword != "" {
if !request.StatusProxyMarketPassword.Empty() {
walletConfig.StatusProxyMarketPassword = request.StatusProxyMarketPassword
}
if request.StatusProxyBlockchainUser != "" {
if !request.StatusProxyBlockchainUser.Empty() {
walletConfig.StatusProxyBlockchainUser = request.StatusProxyBlockchainUser
}
if request.StatusProxyBlockchainPassword != "" {
if !request.StatusProxyBlockchainPassword.Empty() {
walletConfig.StatusProxyBlockchainPassword = request.StatusProxyBlockchainPassword
}

7 changes: 7 additions & 0 deletions internal/security/sensitive_string_test.go
Original file line number Diff line number Diff line change
@@ -64,3 +64,10 @@ func TestCopySensitiveString(t *testing.T) {
sCopy := s
require.Equal(t, secretValue, sCopy.Reveal())
}

func TestCopySensitiveString(t *testing.T) {
secretValue := gofakeit.LetterN(10)
s := NewSensitiveString(secretValue)
sCopy := s
require.Equal(t, secretValue, sCopy.Reveal())
}
53 changes: 19 additions & 34 deletions params/config.go
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ import (
"github.com/status-im/status-go/static"
wakucommon "github.com/status-im/status-go/waku/common"
wakuv2common "github.com/status-im/status-go/wakuv2/common"
"github.com/status-im/status-go/internal/security"
)

// ----------
@@ -303,10 +304,10 @@ type ProviderConfig struct {

// URL sets the rpc upstream host address for communication with
// a non-local infura endpoint.
User string `json:",omitempty"`
Password string `json:",omitempty"`
APIKey string `json:"APIKey,omitempty"`
APIKeySecret string `json:"APIKeySecret,omitempty"`
User security.SensitiveString `json:",omitempty"`
Password security.SensitiveString `json:",omitempty"`
APIKey security.SensitiveString `json:"APIKey,omitempty"`
APIKeySecret security.SensitiveString `json:"APIKeySecret,omitempty"`
}

// ----------
@@ -546,36 +547,20 @@ type Network struct {
// WalletConfig extra configuration for wallet.Service.
type WalletConfig struct {
Enabled bool
OpenseaAPIKey string `json:"OpenseaAPIKey"`
RaribleMainnetAPIKey string `json:"RaribleMainnetAPIKey"`
RaribleTestnetAPIKey string `json:"RaribleTestnetAPIKey"`
AlchemyAPIKeys map[uint64]string `json:"AlchemyAPIKeys"`
InfuraAPIKey string `json:"InfuraAPIKey"`
InfuraAPIKeySecret string `json:"InfuraAPIKeySecret"`
StatusProxyMarketUser string `json:"StatusProxyMarketUser"`
StatusProxyMarketPassword string `json:"StatusProxyMarketPassword"`
StatusProxyBlockchainUser string `json:"StatusProxyBlockchainUser"`
StatusProxyBlockchainPassword string `json:"StatusProxyBlockchainPassword"`
StatusProxyEnabled bool `json:"StatusProxyEnabled"`
StatusProxyStageName string `json:"StatusProxyStageName"`
EnableCelerBridge bool `json:"EnableCelerBridge"`
EnableMercuryoProvider bool `json:"EnableMercuryoProvider"`
}

// MarshalJSON custom marshalling to avoid exposing sensitive data in log,
// there's a function called `startNode` will log NodeConfig which include WalletConfig
func (wc WalletConfig) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Enabled bool `json:"Enabled"`
StatusProxyEnabled bool `json:"StatusProxyEnabled"`
EnableCelerBridge bool `json:"EnableCelerBridge"`
EnableMercuryoProvider bool `json:"EnableMercuryoProvider"`
}{
Enabled: wc.Enabled,
StatusProxyEnabled: wc.StatusProxyEnabled,
EnableCelerBridge: wc.EnableCelerBridge,
EnableMercuryoProvider: wc.EnableMercuryoProvider,
})
OpenseaAPIKey security.SensitiveString `json:"OpenseaAPIKey"`
RaribleMainnetAPIKey security.SensitiveString `json:"RaribleMainnetAPIKey"`
RaribleTestnetAPIKey security.SensitiveString `json:"RaribleTestnetAPIKey"`
AlchemyAPIKeys map[uint64]security.SensitiveString `json:"AlchemyAPIKeys"`
InfuraAPIKey security.SensitiveString `json:"InfuraAPIKey"`
InfuraAPIKeySecret security.SensitiveString `json:"InfuraAPIKeySecret"`
StatusProxyMarketUser security.SensitiveString `json:"StatusProxyMarketUser"`
StatusProxyMarketPassword security.SensitiveString `json:"StatusProxyMarketPassword"`
StatusProxyBlockchainUser security.SensitiveString `json:"StatusProxyBlockchainUser"`
StatusProxyBlockchainPassword security.SensitiveString `json:"StatusProxyBlockchainPassword"`
StatusProxyEnabled bool `json:"StatusProxyEnabled"`
StatusProxyStageName string `json:"StatusProxyStageName"`
EnableCelerBridge bool `json:"EnableCelerBridge"`
EnableMercuryoProvider bool `json:"EnableMercuryoProvider"`
}

// LocalNotificationsConfig extra configuration for localnotifications.Service.
6 changes: 4 additions & 2 deletions params/config_test.go
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@ import (

"github.com/status-im/status-go/params"
"github.com/status-im/status-go/t/utils"
"github.com/status-im/status-go/internal/security"
"github.com/brianvoe/gofakeit/v6"
)

func TestNewNodeConfigWithDefaults(t *testing.T) {
@@ -315,8 +317,8 @@ func TestNodeConfigValidate(t *testing.T) {

func TestMarshalWalletConfigJSON(t *testing.T) {
walletConfig := params.WalletConfig{
OpenseaAPIKey: "some-key",
RaribleMainnetAPIKey: "some-key2",
OpenseaAPIKey: security.NewSensitiveString(gofakeit.LetterN(10)),
RaribleMainnetAPIKey: security.NewSensitiveString(gofakeit.LetterN(10)),
}
bytes, err := json.Marshal(walletConfig)
require.NoError(t, err)
3 changes: 2 additions & 1 deletion protocol/communities/manager_test.go
Original file line number Diff line number Diff line change
@@ -36,6 +36,7 @@ import (
_ "github.com/mutecomm/go-sqlcipher/v4" // require go-sqlcipher that overrides default implementation
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
"github.com/status-im/status-go/internal/security"
)

func TestManagerSuite(t *testing.T) {
@@ -220,7 +221,7 @@ func (s *ManagerSuite) setupManagerForTokenPermissions() (*Manager, *testCollect

options := []ManagerOption{
WithWalletConfig(&params.WalletConfig{
OpenseaAPIKey: "some-key",
OpenseaAPIKey: security.NewSensitiveString("some-key"),
}),
WithCollectiblesManager(cm),
WithTokenManager(tm),
39 changes: 20 additions & 19 deletions protocol/requests/create_account.go
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import (

utils "github.com/status-im/status-go/common"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/internal/security"
)

var ErrCreateAccountInvalidDisplayName = errors.New("create-account: invalid display name")
@@ -89,25 +90,25 @@ type CreateAccount struct {
}

type WalletSecretsConfig struct {
PoktToken string `json:"poktToken"`
InfuraToken string `json:"infuraToken"`
InfuraSecret string `json:"infuraSecret"`
OpenseaAPIKey string `json:"openseaApiKey"`
RaribleMainnetAPIKey string `json:"raribleMainnetApiKey"`
RaribleTestnetAPIKey string `json:"raribleTestnetApiKey"`

AlchemyEthereumMainnetToken string `json:"alchemyEthereumMainnetToken"`
AlchemyEthereumSepoliaToken string `json:"alchemyEthereumSepoliaToken"`
AlchemyArbitrumMainnetToken string `json:"alchemyArbitrumMainnetToken"`
AlchemyArbitrumSepoliaToken string `json:"alchemyArbitrumSepoliaToken"`
AlchemyOptimismMainnetToken string `json:"alchemyOptimismMainnetToken"`
AlchemyOptimismSepoliaToken string `json:"alchemyOptimismSepoliaToken"`

StatusProxyStageName string `json:"statusProxyStageName"`
StatusProxyMarketUser string `json:"statusProxyMarketUser"`
StatusProxyMarketPassword string `json:"statusProxyMarketPassword"`
StatusProxyBlockchainUser string `json:"statusProxyBlockchainUser"`
StatusProxyBlockchainPassword string `json:"statusProxyBlockchainPassword"`
PoktToken string `json:"poktToken"`
InfuraToken security.SensitiveString `json:"infuraToken"`
InfuraSecret security.SensitiveString `json:"infuraSecret"`
OpenseaAPIKey security.SensitiveString `json:"openseaApiKey"`
RaribleMainnetAPIKey security.SensitiveString `json:"raribleMainnetApiKey"`
RaribleTestnetAPIKey security.SensitiveString `json:"raribleTestnetApiKey"`

AlchemyEthereumMainnetToken security.SensitiveString `json:"alchemyEthereumMainnetToken"`
AlchemyEthereumSepoliaToken security.SensitiveString `json:"alchemyEthereumSepoliaToken"`
AlchemyArbitrumMainnetToken security.SensitiveString `json:"alchemyArbitrumMainnetToken"`
AlchemyArbitrumSepoliaToken security.SensitiveString `json:"alchemyArbitrumSepoliaToken"`
AlchemyOptimismMainnetToken security.SensitiveString `json:"alchemyOptimismMainnetToken"`
AlchemyOptimismSepoliaToken security.SensitiveString `json:"alchemyOptimismSepoliaToken"`

StatusProxyStageName string `json:"statusProxyStageName"`
StatusProxyMarketUser security.SensitiveString `json:"statusProxyMarketUser"`
StatusProxyMarketPassword security.SensitiveString `json:"statusProxyMarketPassword"`
StatusProxyBlockchainUser security.SensitiveString `json:"statusProxyBlockchainUser"`
StatusProxyBlockchainPassword security.SensitiveString `json:"statusProxyBlockchainPassword"`

// Testing
GanacheURL string `json:"ganacheURL"`
2 changes: 1 addition & 1 deletion rpc/client.go
Original file line number Diff line number Diff line change
@@ -295,7 +295,7 @@ func (c *Client) getEthClients(network *params.Network) []ethclient.RPSLimitedEt
// For now, we only support auth for status-proxy.
var opts []gethrpc.ClientOption
if provider.authenticationNeeded() {
authEncoded := base64.StdEncoding.EncodeToString([]byte(provider.Auth))
authEncoded := base64.StdEncoding.EncodeToString([]byte(provider.Auth.Reveal()))
opts = append(opts,
gethrpc.WithHeaders(http.Header{
"Authorization": {"Basic " + authEncoded},
13 changes: 7 additions & 6 deletions rpc/provider.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import (
"go.uber.org/zap"

"github.com/status-im/status-go/params"
"github.com/status-im/status-go/internal/security"
)

const (
@@ -21,12 +22,12 @@ const (
type Provider struct {
Key string
URL string
Auth string
Auth security.SensitiveString
Priority int
}

func (p Provider) authenticationNeeded() bool {
return len(p.Auth) > 0
return !p.Auth.Empty()
}

func getProviderPriorityByURL(url string) int {
@@ -58,7 +59,7 @@ func getProviderConfig(providerConfigs []params.ProviderConfig, providerName str
return params.ProviderConfig{}, fmt.Errorf("provider config not found for provider: %s", providerName)
}

func createProvider(key, url, credentials string, providers *[]Provider) {
func createProvider(key, url string, credentials security.SensitiveString, providers *[]Provider) {
priority := getProviderPriorityByURL(url)
*providers = append(*providers, Provider{
Key: key,
@@ -78,12 +79,12 @@ func (c *Client) prepareProviders(network *params.Network) []Provider {
}

// Add main and fallback providers
createProvider(ProviderMain, network.RPCURL, "", &providers)
createProvider(ProviderFallback, network.FallbackURL, "", &providers)
createProvider(ProviderMain, network.RPCURL, security.NewSensitiveString(""), &providers)
createProvider(ProviderFallback, network.FallbackURL, security.NewSensitiveString(""), &providers)

// If the proxy provider is enabled, add it and its fallback options
if proxyProvider.Enabled {
credentials := proxyProvider.User + ":" + proxyProvider.Password
credentials := security.NewSensitiveString(proxyProvider.User.Reveal() + ":" + proxyProvider.Password.Reveal())
createProvider(ProviderStatusProxy, network.DefaultRPCURL, credentials, &providers)
createProvider(ProviderStatusProxyFallback, network.DefaultFallbackURL, credentials, &providers)
createProvider(ProviderStatusProxyFallback2, network.DefaultFallbackURL2, credentials, &providers)
Loading