Skip to content

Commit

Permalink
Merge branch 'master' into encoding_swap
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan O'Hara-Reid committed Jan 8, 2025
2 parents 2d08549 + fcd78ad commit 1a82764
Show file tree
Hide file tree
Showing 105 changed files with 233,318 additions and 159,504 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/proto-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
- uses: bufbuild/buf-setup-action@v1.47.2
- uses: bufbuild/buf-setup-action@v1.48.0

- name: buf generate
working-directory: ./gctrpc
Expand Down
203 changes: 149 additions & 54 deletions cmd/config/config.go
Original file line number Diff line number Diff line change
@@ -1,82 +1,177 @@
package main

import (
"errors"
"flag"
"log"
"fmt"
"os"
"slices"
"strings"

"github.com/buger/jsonparser"
"github.com/thrasher-corp/gocryptotrader/common/file"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
)

// EncryptOrDecrypt returns a string from a boolean
func EncryptOrDecrypt(encrypt bool) string {
if encrypt {
return "encrypted"
}
return "decrypted"
}
var commands = []string{"upgrade", "encrypt", "decrypt"}

func main() {
var inFile, outFile, key string
var encrypt bool
fmt.Println("GoCryptoTrader: config-helper tool")

defaultCfgFile := config.DefaultFilePath()
flag.StringVar(&inFile, "infile", defaultCfgFile, "The config input file to process.")
flag.StringVar(&outFile, "outfile", defaultCfgFile+".out", "The config output file.")
flag.BoolVar(&encrypt, "encrypt", true, "Whether to encrypt or decrypt.")
flag.StringVar(&key, "key", "", "The key to use for AES encryption.")
flag.Parse()

log.Println("GoCryptoTrader: config-helper tool.")

if key == "" {
result, err := config.PromptForConfigKey(false)
if err != nil {
log.Fatalf("Unable to obtain encryption/decryption key: %s", err)
}
key = string(result)

var in, out, keyStr string
var inplace bool

fs := flag.NewFlagSet("config", flag.ExitOnError)
fs.Usage = func() { usage(fs) }
fs.StringVar(&in, "in", defaultCfgFile, "The config input file to process")
fs.StringVar(&out, "out", "[in].out", "The config output file")
fs.BoolVar(&inplace, "edit", false, "Edit; Save result to the original file")
fs.StringVar(&keyStr, "key", "", "The key to use for AES encryption")

cmd, args := parseCommand(os.Args[1:])
if cmd == "" {
usage(fs)
os.Exit(2)
}

if err := fs.Parse(args); err != nil {
fatal(err.Error())
}

if inplace {
out = in
} else if out == "[in].out" {
out = in + ".out"
}

key := []byte(keyStr)
var err error
switch cmd {
case "upgrade":
err = upgradeFile(in, out, key)
case "decrypt":
err = encryptWrapper(in, out, key, false, decryptFile)
case "encrypt":
err = encryptWrapper(in, out, key, true, encryptFile)
}

fileData, err := os.ReadFile(inFile)
if err != nil {
log.Fatalf("Unable to read input file %s. Error: %s.", inFile, err)
fatal(err.Error())
}

if config.ConfirmECS(fileData) && encrypt {
log.Println("File is already encrypted. Decrypting..")
encrypt = false
fmt.Println("Success! File written to " + out)
}

func upgradeFile(in, out string, key []byte) error {
c := &config.Config{
EncryptionKeyProvider: func(_ bool) ([]byte, error) {
if len(key) != 0 {
return key, nil
}
return config.PromptForConfigKey(false)
},
}

if !config.ConfirmECS(fileData) && !encrypt {
var result interface{}
errf := json.Unmarshal(fileData, &result)
if errf != nil {
log.Fatal(errf)
}
log.Println("File is already decrypted. Encrypting..")
encrypt = true
if err := c.ReadConfigFromFile(in, true); err != nil {
return err
}

var data []byte
if encrypt {
data, err = config.EncryptConfigFile(fileData, []byte(key))
if err != nil {
log.Fatalf("Unable to encrypt config data. Error: %s.", err)
}
} else {
data, err = config.DecryptConfigFile(fileData, []byte(key))
if err != nil {
log.Fatalf("Unable to decrypt config data. Error: %s.", err)
return c.SaveConfigToFile(out)
}

type encryptFunc func(string, []byte) ([]byte, error)

func encryptWrapper(in, out string, key []byte, confirmKey bool, fn encryptFunc) error {
if len(key) == 0 {
var err error
if key, err = config.PromptForConfigKey(confirmKey); err != nil {
return err
}
}
outData, err := fn(in, key)
if err != nil {
return err
}
if err := file.Write(out, outData); err != nil {
return fmt.Errorf("unable to write output file %s; Error: %w", out, err)
}
return nil
}

func encryptFile(in string, key []byte) ([]byte, error) {
if config.IsFileEncrypted(in) {
return nil, errors.New("file is already encrypted")
}
outData, err := config.EncryptConfigFile(readFile(in), key)
if err != nil {
return nil, fmt.Errorf("unable to encrypt config data. Error: %w", err)
}
return outData, nil
}

func decryptFile(in string, key []byte) ([]byte, error) {
if !config.IsFileEncrypted(in) {
return nil, errors.New("file is already decrypted")
}
outData, err := config.DecryptConfigFile(readFile(in), key)
if err != nil {
return nil, fmt.Errorf("unable to decrypt config data. Error: %w", err)
}
if outData, err = jsonparser.Set(outData, []byte("-1"), "encryptConfig"); err != nil {
return nil, fmt.Errorf("unable to decrypt config data. Error: %w", err)
}
return outData, nil
}

err = file.Write(outFile, data)
func readFile(in string) []byte {
fileData, err := os.ReadFile(in)
if err != nil {
log.Fatalf("Unable to write output file %s. Error: %s", outFile, err)
fatal("Unable to read input file " + in + "; Error: " + err.Error())
}
log.Printf(
"Successfully %s input file %s and wrote output to %s.\n",
EncryptOrDecrypt(encrypt), inFile, outFile,
)
return fileData
}

func fatal(msg string) {
fmt.Fprintln(os.Stderr, msg)
os.Exit(2)
}

// parseCommand will return the single non-flag parameter from os.Args, and return the remaining args
// If none is provided, too many, usage() will be called and exit 1
func parseCommand(a []string) (cmd string, args []string) {
cmds, rem := []string{}, []string{}
for _, s := range a {
if slices.Contains(commands, s) {
cmds = append(cmds, s)
} else {
rem = append(rem, s)
}
}
switch len(cmds) {
case 0:
fmt.Fprintln(os.Stderr, "No command provided")
case 1: //
return cmds[0], rem
default:
fmt.Fprintln(os.Stderr, "Too many commands provided: "+strings.Join(cmds, ", "))
}
return "", nil
}

// usage prints command usage and exits 1
func usage(fs *flag.FlagSet) {
//nolint:dupword // deliberate duplication of commands
fmt.Fprintln(os.Stderr, `
Usage:
config [arguments] <command>
The commands are:
encrypt encrypt infile and write to outfile
decrypt decrypt infile and write to outfile
upgrade upgrade the version of a decrypted config file
The arguments are:`)
fs.PrintDefaults()
}
18 changes: 0 additions & 18 deletions cmd/config/config_test.go

This file was deleted.

21 changes: 16 additions & 5 deletions cmd/documentation/exchanges_templates/deribit.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,23 @@ if err != nil {
}
```

### How to do Websocket public/private calls
### Subscriptions

```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
All default subscriptions are for all enabled assets.

Default Public Subscriptions:
- Candles ( Timeframe: 1 day )
- Orderbook ( Full depth @ Interval: 100ms )
- Ticker ( Interval: 100ms )
- All Trades ( Interval: 100ms )

Default Authenticated Subscriptions:
- My Account Orders
- My Account Trades

kline.Raw Interval configurable for a raw orderbook subscription when authenticated

Subscriptions are subject to enabled assets and pairs.

### Please click GoDocs chevron above to view current GoDoc information for this package
{{template "contributions"}}
Expand Down
22 changes: 17 additions & 5 deletions cmd/documentation/exchanges_templates/hitbtc.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,24 @@ if err != nil {
}
```

### How to do Websocket public/private calls
### Subscriptions

```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
Subscriptions are for [v2 api](https://hitbtc-com.github.io/hitbtc-api/#socket-api-reference)

All subscriptions are for spot.

Default Public Subscriptions:
- Ticker
- Orderbook
- Candles ( Interval: 30 minutes, History: 100 )
- All Trades ( History: 100 )

Default Authenticated Subscriptions:
- My Account events

Subscriptions are subject to enabled assets and pairs.

Configure Levels for number of history entries to return for applicable APIs.

### Please click GoDocs chevron above to view current GoDoc information for this package
{{template "contributions"}}
Expand Down
2 changes: 2 additions & 0 deletions common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ var (
ErrNoResponse = errors.New("no response")
ErrTypeAssertFailure = errors.New("type assert failure")
ErrUnknownError = errors.New("unknown error")
ErrGettingField = errors.New("error getting field")
ErrSettingField = errors.New("error setting field")
)

var (
Expand Down
Loading

0 comments on commit 1a82764

Please sign in to comment.