Skip to content

Commit

Permalink
context: Add authenticated HTTP credentials (thrasher-corp#892)
Browse files Browse the repository at this point in the history
* gRPC: context overide

* exchanges: continue update

* exchange: Update context handling
*Add setter methods for API credentials
*Shift credentials functionality to its own file in exchanges package
*Add tests
*Refactor function DeployCredentialsToContext for library usage
*Add function to process credential metadata from API boundary to internal use context value.
*Add OTP rpc handling

* exchanges: reverts to old style in GetFeeByType, reverts some code I accidently deleted. Plus things and other. XD

* template: update

* exchanges: fix linter issues

* REMOVE THAT AWESOME NEW LINE!

* gct: fix some tests

* I cant spell :(

* exchanges/gctscript: fix more tests

* coinnut: fix tests

* Update exchanges/credentials.go

Co-authored-by: Scott <[email protected]>

* Update exchanges/credentials.go

Co-authored-by: Scott <[email protected]>

* Update exchanges/credentials.go

Co-authored-by: Scott <[email protected]>

* Update exchanges/credentials.go

Co-authored-by: Scott <[email protected]>

* Update exchanges/credentials.go

Co-authored-by: Scott <[email protected]>

* glorious: nits

* exchanges/gctcli: stop applying empty credentials

* fix linters

* exchanges: add test

* rpceserver: actually check error for errors

* rpcserver: fix up tests

* Update exchanges/credentials.go

Co-authored-by: Scott <[email protected]>

* exchanges/creds: move tests to corresponding files, add protection and segration for Credentials struct & ptr values

* exchanges/creds: allow subaccount to override default credentials via gRPC

* exchanges/credentials: don't return nil in GetCredentials

* creds: spelling

* exchanges: fix glorious NITS!

* credentials: Add in test and refactor IsEmpty method.

* credentials: change type positioning (glorious)

* exchange_template: Fix template changes

* DOCS: Refresh

* docs: fix spelling

* DOCS: fix alignment and add package

* DOCS: ALIGN!

Co-authored-by: Ryan O'Hara-Reid <[email protected]>
Co-authored-by: Scott <[email protected]>
  • Loading branch information
3 people authored Mar 21, 2022
1 parent 58b9f8b commit 09fa2f2
Show file tree
Hide file tree
Showing 122 changed files with 3,001 additions and 2,121 deletions.
15 changes: 8 additions & 7 deletions backtester/backtest/backtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ func (bt *BackTest) loadExchangePairAssetBase(exch, base, quote, ass string) (gc
}

exchangeBase := e.GetBase()
if !exchangeBase.ValidateAPICredentials() {
if exchangeBase.ValidateAPICredentials(exchangeBase.GetDefaultCredentials()) != nil {
log.Warnf(log.BackTester, "no credentials set for %v, this is theoretical only", exchangeBase.Name)
}

Expand Down Expand Up @@ -801,21 +801,22 @@ func loadLiveData(cfg *config.Config, base *gctexchange.Base) error {
}

if cfg.DataSettings.LiveData.APIKeyOverride != "" {
base.API.Credentials.Key = cfg.DataSettings.LiveData.APIKeyOverride
base.API.SetKey(cfg.DataSettings.LiveData.APIKeyOverride)
}
if cfg.DataSettings.LiveData.APISecretOverride != "" {
base.API.Credentials.Secret = cfg.DataSettings.LiveData.APISecretOverride
base.API.SetSecret(cfg.DataSettings.LiveData.APISecretOverride)
}
if cfg.DataSettings.LiveData.APIClientIDOverride != "" {
base.API.Credentials.ClientID = cfg.DataSettings.LiveData.APIClientIDOverride
base.API.SetClientID(cfg.DataSettings.LiveData.APIClientIDOverride)
}
if cfg.DataSettings.LiveData.API2FAOverride != "" {
base.API.Credentials.PEMKey = cfg.DataSettings.LiveData.API2FAOverride
base.API.SetPEMKey(cfg.DataSettings.LiveData.API2FAOverride)
}
if cfg.DataSettings.LiveData.APISubAccountOverride != "" {
base.API.Credentials.Subaccount = cfg.DataSettings.LiveData.APISubAccountOverride
base.API.SetSubAccount(cfg.DataSettings.LiveData.APISubAccountOverride)
}
validated := base.ValidateAPICredentials()

validated := base.AreCredentialsValid(context.TODO())
base.API.AuthenticatedSupport = validated
if !validated && cfg.DataSettings.LiveData.RealOrders {
log.Warn(log.BackTester, "invalid API credentials set, real orders set to false")
Expand Down
8 changes: 1 addition & 7 deletions backtester/backtest/backtest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,13 +381,6 @@ func TestLoadLiveData(t *testing.T) {
AuthenticatedSupport: false,
AuthenticatedWebsocketSupport: false,
PEMKeySupport: false,
Credentials: struct {
Key string
Secret string
ClientID string
PEMKey string
Subaccount string
}{},
CredentialsValidator: struct {
RequiresPEM bool
RequiresKey bool
Expand All @@ -403,6 +396,7 @@ func TestLoadLiveData(t *testing.T) {
},
},
}

err = loadLiveData(cfg, b)
if !errors.Is(err, common.ErrNilArguments) {
t.Error(err)
Expand Down
12 changes: 6 additions & 6 deletions backtester/eventhandlers/exchange/exchange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ func TestPlaceOrder(t *testing.T) {
}

_, err = e.placeOrder(context.Background(), decimal.NewFromInt(1), decimal.NewFromInt(1), true, true, f, bot.OrderManager)
if err != nil && !strings.Contains(err.Error(), "unset/default API keys") {
t.Error(err)
if !errors.Is(err, exchange.ErrAuthenticationSupportNotEnabled) {
t.Errorf("received: %v but expected: %v", err, exchange.ErrAuthenticationSupportNotEnabled)
}
}

Expand Down Expand Up @@ -293,8 +293,8 @@ func TestExecuteOrder(t *testing.T) {
o.Direction = gctorder.Sell
e.CurrencySettings = []Settings{cs}
_, err = e.ExecuteOrder(o, d, bot.OrderManager, &fakeFund{})
if err != nil && !strings.Contains(err.Error(), "unset/default API keys") {
t.Error(err)
if !errors.Is(err, exchange.ErrAuthenticationSupportNotEnabled) {
t.Errorf("received: %v but expected: %v", err, exchange.ErrAuthenticationSupportNotEnabled)
}
}

Expand Down Expand Up @@ -468,8 +468,8 @@ func TestExecuteOrderBuySellSizeLimit(t *testing.T) {
o.Direction = gctorder.Sell
e.CurrencySettings = []Settings{cs}
_, err = e.ExecuteOrder(o, d, bot.OrderManager, &fakeFund{})
if !errors.Is(err, exchange.ErrAuthenticatedRequestWithoutCredentialsSet) {
t.Errorf("received %v expected %v", err, exchange.ErrAuthenticatedRequestWithoutCredentialsSet)
if !errors.Is(err, exchange.ErrAuthenticationSupportNotEnabled) {
t.Errorf("received: %v but expected: %v", err, exchange.ErrAuthenticationSupportNotEnabled)
}
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/exchange_template/test_file.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestInterface(t *testing.T) {
}

func areTestAPIKeysSet() bool {
return {{.Variable}}.ValidateAPICredentials()
return {{.Variable}}.ValidateAPICredentials({{.Variable}}.GetDefaultCredentials()) == nil
}

// Implement tests for API endpoints below
Expand Down
5 changes: 4 additions & 1 deletion cmd/exchange_template/wrapper_file.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,11 @@ func ({{.Variable}} *{{.CapitalName}}) SetDefaults() {
},
}
// NOTE: SET THE EXCHANGES RATE LIMIT HERE
{{.Variable}}.Requester = request.New({{.Variable}}.Name,
{{.Variable}}.Requester, err = request.New({{.Variable}}.Name,
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
if err != nil {
log.Errorln(log.ExchangeSys, err)
}

// NOTE: SET THE URLs HERE
{{.Variable}}.API.Endpoints = {{.Variable}}.NewEndpoints()
Expand Down
50 changes: 24 additions & 26 deletions cmd/exchange_wrapper_issues/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,45 +202,43 @@ func shouldLoadExchange(name string) bool {
func setExchangeAPIKeys(name string, keys map[string]*config.APICredentialsConfig, base *exchange.Base) bool {
lowerExchangeName := strings.ToLower(name)

if base.API.CredentialsValidator.RequiresKey && keys[lowerExchangeName].Key == "" {
keys[lowerExchangeName].Key = config.DefaultAPIKey
creds, ok := keys[lowerExchangeName]
if !ok {
log.Printf("%s credentials not found in keys map\n", name)
return false
}
if base.API.CredentialsValidator.RequiresSecret && keys[lowerExchangeName].Secret == "" {
keys[lowerExchangeName].Secret = config.DefaultAPISecret

if base.API.CredentialsValidator.RequiresKey && creds.Key == "" {
creds.Key = config.DefaultAPIKey
}
if base.API.CredentialsValidator.RequiresPEM && keys[lowerExchangeName].PEMKey == "" {
keys[lowerExchangeName].PEMKey = "PEM"
if base.API.CredentialsValidator.RequiresSecret && creds.Secret == "" {
creds.Secret = config.DefaultAPISecret
}
if base.API.CredentialsValidator.RequiresClientID && keys[lowerExchangeName].ClientID == "" {
keys[lowerExchangeName].ClientID = config.DefaultAPIClientID
if base.API.CredentialsValidator.RequiresPEM && creds.PEMKey == "" {
creds.PEMKey = "PEM"
}
if keys[lowerExchangeName].OTPSecret == "" {
keys[lowerExchangeName].OTPSecret = "-" // Ensure OTP is available for use
if base.API.CredentialsValidator.RequiresClientID && creds.ClientID == "" {
creds.ClientID = config.DefaultAPIClientID
}
if creds.OTPSecret == "" {
creds.OTPSecret = "-" // Ensure OTP is available for use
}

base.API.Credentials.Key = keys[lowerExchangeName].Key
base.Config.API.Credentials.Key = keys[lowerExchangeName].Key

base.API.Credentials.Secret = keys[lowerExchangeName].Secret
base.Config.API.Credentials.Secret = keys[lowerExchangeName].Secret

base.API.Credentials.ClientID = keys[lowerExchangeName].ClientID
base.Config.API.Credentials.ClientID = keys[lowerExchangeName].ClientID
base.SetCredentials(creds.Key, creds.Secret, creds.ClientID, creds.Subaccount, creds.PEMKey, creds.OTPSecret)

if keys[lowerExchangeName].OTPSecret != "-" {
base.Config.API.Credentials.OTPSecret = keys[lowerExchangeName].OTPSecret
}
if keys[lowerExchangeName].Subaccount != "" {
base.API.Credentials.Subaccount = keys[lowerExchangeName].Subaccount
base.Config.API.Credentials.Subaccount = keys[lowerExchangeName].Subaccount
}
base.Config.API.Credentials.Key = creds.Key
base.Config.API.Credentials.Secret = creds.Secret
base.Config.API.Credentials.ClientID = creds.ClientID
base.Config.API.Credentials.Subaccount = creds.Subaccount
base.Config.API.Credentials.PEMKey = creds.PEMKey
base.Config.API.Credentials.OTPSecret = creds.OTPSecret

base.API.AuthenticatedSupport = true
base.API.AuthenticatedWebsocketSupport = true
base.Config.API.AuthenticatedSupport = true
base.Config.API.AuthenticatedWebsocketSupport = true

return base.ValidateAPICredentials()
return base.ValidateAPICredentials(base.GetDefaultCredentials()) == nil
}

func parseOrderSide(orderSide string) order.Side {
Expand Down
15 changes: 1 addition & 14 deletions cmd/gctcli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -4925,7 +4925,7 @@ func getFuturesPositions(c *cli.Context) error {
var getCollateralCommand = &cli.Command{
Name: "getcollateral",
Usage: "returns total collateral for an exchange asset, with optional per currency breakdown",
ArgsUsage: "<exchange> <asset> <calculateoffline> <includebreakdown> <includezerovalues> <subaccount>",
ArgsUsage: "<exchange> <asset> <calculateoffline> <includebreakdown> <includezerovalues>",
Action: getCollateral,
Flags: []cli.Flag{
&cli.StringFlag{
Expand Down Expand Up @@ -4953,11 +4953,6 @@ var getCollateralCommand = &cli.Command{
Aliases: []string{"z"},
Usage: "include collateral values that are zero",
},
&cli.StringFlag{
Name: "subaccount",
Aliases: []string{"s"},
Usage: "the subaccount to retrieve collateral data from, depending on individual exchange support",
},
},
}

Expand Down Expand Up @@ -5015,13 +5010,6 @@ func getCollateral(c *cli.Context) error {
}
}

var subAccount string
if c.IsSet("subaccount") {
subAccount = c.String("subaccount")
} else if c.Args().Get(5) != "" {
subAccount = c.Args().Get(5)
}

conn, cancel, err := setupClient(c)
if err != nil {
return err
Expand All @@ -5033,7 +5021,6 @@ func getCollateral(c *cli.Context) error {
&gctrpc.GetCollateralRequest{
Exchange: exchangeName,
Asset: assetType,
SubAccount: subAccount,
IncludeBreakdown: includeBreakdown,
CalculateOffline: calculateOffline,
IncludeZeroValues: includeZeroValues,
Expand Down
37 changes: 37 additions & 0 deletions cmd/gctcli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import (

"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/core"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/gctrpc/auth"
"github.com/thrasher-corp/gocryptotrader/signaler"
"github.com/urfave/cli/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
)

var (
Expand All @@ -26,6 +28,7 @@ var (
pairDelimiter string
certPath string
timeout time.Duration
exchangeCreds exchange.Credentials
)

const defaultTimeout = time.Second * 30
Expand Down Expand Up @@ -53,6 +56,10 @@ func setupClient(c *cli.Context) (*grpc.ClientConn, context.CancelFunc, error) {

var cancel context.CancelFunc
c.Context, cancel = context.WithTimeout(c.Context, timeout)
if !exchangeCreds.IsEmpty() {
flag, values := exchangeCreds.GetMetaData()
c.Context = metadata.AppendToOutgoingContext(c.Context, flag, values)
}
conn, err := grpc.DialContext(c.Context, host, opts...)
return conn, cancel, err
}
Expand Down Expand Up @@ -100,6 +107,36 @@ func main() {
Usage: "the default context timeout value for requests",
Destination: &timeout,
},
&cli.StringFlag{
Name: "apikey",
Usage: "override config API key for request",
Destination: &exchangeCreds.Key,
},
&cli.StringFlag{
Name: "apisecret",
Usage: "override config API Secret for request",
Destination: &exchangeCreds.Secret,
},
&cli.StringFlag{
Name: "apisubaccount",
Usage: "override config API sub account for request",
Destination: &exchangeCreds.SubAccount,
},
&cli.StringFlag{
Name: "apiclientid",
Usage: "override config API client ID for request",
Destination: &exchangeCreds.ClientID,
},
&cli.StringFlag{
Name: "apipemkey",
Usage: "override config API PEM key for request",
Destination: &exchangeCreds.PEMKey,
},
&cli.StringFlag{
Name: "apionetimepassword",
Usage: "override config API One Time Password (OTP) for request",
Destination: &exchangeCreds.OneTimePassword,
},
}
app.Commands = []*cli.Command{
getInfoCommand,
Expand Down
Loading

0 comments on commit 09fa2f2

Please sign in to comment.