Skip to content

Commit

Permalink
op-service: Add optional headers to the signer client (ethereum-optim…
Browse files Browse the repository at this point in the history
…ism#12407)

* op-service: Add optional headers to the signer client

* Explain flag usage
  • Loading branch information
trianglesphere authored and samlaf committed Nov 10, 2024
1 parent 01f7a4e commit be5b9c6
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 5 deletions.
21 changes: 21 additions & 0 deletions op-service/signer/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package signer

import (
"errors"
"net/http"
"strings"

"github.com/urfave/cli/v2"

Expand All @@ -12,6 +14,7 @@ import (
const (
EndpointFlagName = "signer.endpoint"
AddressFlagName = "signer.address"
HeadersFlagName = "signer.header"
)

func CLIFlags(envPrefix string) []cli.Flag {
Expand All @@ -27,6 +30,11 @@ func CLIFlags(envPrefix string) []cli.Flag {
Usage: "Address the signer is signing transactions for",
EnvVars: opservice.PrefixEnvVar(envPrefix, "ADDRESS"),
},
&cli.StringSliceFlag{
Name: HeadersFlagName,
Usage: "Headers to pass to the remote signer. Format `key=value`. Value can contain any character allowed in a HTTP header. When using env vars, split with commas. When using flags one key value pair per flag.",
EnvVars: opservice.PrefixEnvVar(envPrefix, "HEADER"),
},
}
flags = append(flags, optls.CLIFlagsWithFlagPrefix(envPrefix, "signer")...)
return flags
Expand All @@ -35,11 +43,13 @@ func CLIFlags(envPrefix string) []cli.Flag {
type CLIConfig struct {
Endpoint string
Address string
Headers http.Header
TLSConfig optls.CLIConfig
}

func NewCLIConfig() CLIConfig {
return CLIConfig{
Headers: http.Header{},
TLSConfig: optls.NewCLIConfig(),
}
}
Expand All @@ -62,9 +72,20 @@ func (c CLIConfig) Enabled() bool {
}

func ReadCLIConfig(ctx *cli.Context) CLIConfig {
var headers = http.Header{}
if ctx.StringSlice(HeadersFlagName) != nil {
for _, header := range ctx.StringSlice(HeadersFlagName) {
args := strings.SplitN(header, "=", 2)
if len(args) == 2 {
headers.Set(args[0], args[1])
}
}
}

cfg := CLIConfig{
Endpoint: ctx.String(EndpointFlagName),
Address: ctx.String(AddressFlagName),
Headers: headers,
TLSConfig: optls.ReadCLIConfigWithPrefix(ctx, "signer"),
}
return cfg
Expand Down
35 changes: 35 additions & 0 deletions op-service/signer/cli_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package signer

import (
"net/http"
"testing"

"github.com/stretchr/testify/require"
Expand All @@ -18,6 +19,37 @@ func TestDefaultConfigIsValid(t *testing.T) {
require.NoError(t, err)
}

func TestHeaderParsing(t *testing.T) {
testHeaders := []string{
"test-key=this:is:a:value",
"b64-test-key=value:dGVzdCBkYXRhIDE=$",
}

args := []string{"app", "--signer.header", testHeaders[0], "--signer.header", testHeaders[1]}
cfg := configForArgs(args...)

expectedHeaders := http.Header{}
expectedHeaders.Set("test-key", "this:is:a:value")
expectedHeaders.Set("b64-test-key", "value:dGVzdCBkYXRhIDE=$")

require.Equal(t, expectedHeaders, cfg.Headers)
}

func TestHeaderParsingWithComma(t *testing.T) {
testHeaders := []string{
"test-key=this:is:a:value,b64-test-key=value:dGVzdCBkYXRhIDE=$",
}

args := []string{"app", "--signer.header", testHeaders[0]}
cfg := configForArgs(args...)

expectedHeaders := http.Header{}
expectedHeaders.Set("test-key", "this:is:a:value")
expectedHeaders.Set("b64-test-key", "value:dGVzdCBkYXRhIDE=$")

require.Equal(t, expectedHeaders, cfg.Headers)
}

func TestInvalidConfig(t *testing.T) {
tests := []struct {
name string
Expand All @@ -29,20 +61,23 @@ func TestInvalidConfig(t *testing.T) {
expected: "signer endpoint and address must both be set or not set",
configChange: func(config *CLIConfig) {
config.Address = "0x1234"
config.TLSConfig.Enabled = true
},
},
{
name: "MissingAddress",
expected: "signer endpoint and address must both be set or not set",
configChange: func(config *CLIConfig) {
config.Endpoint = "http://localhost"
config.TLSConfig.Enabled = true
},
},
{
name: "InvalidTLSConfig",
expected: "all tls flags must be set if at least one is set",
configChange: func(config *CLIConfig) {
config.TLSConfig.TLSKey = ""
config.TLSConfig.Enabled = true
},
},
}
Expand Down
8 changes: 4 additions & 4 deletions op-service/signer/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ type SignerClient struct {
logger log.Logger
}

func NewSignerClient(logger log.Logger, endpoint string, tlsConfig optls.CLIConfig) (*SignerClient, error) {
func NewSignerClient(logger log.Logger, endpoint string, headers http.Header, tlsConfig optls.CLIConfig) (*SignerClient, error) {
var httpClient *http.Client
if tlsConfig.TLSCaCert != "" {
if tlsConfig.Enabled {
logger.Info("tlsConfig specified, loading tls config")
caCert, err := os.ReadFile(tlsConfig.TLSCaCert)
if err != nil {
Expand Down Expand Up @@ -63,7 +63,7 @@ func NewSignerClient(logger log.Logger, endpoint string, tlsConfig optls.CLIConf
httpClient = http.DefaultClient
}

rpcClient, err := rpc.DialOptions(context.Background(), endpoint, rpc.WithHTTPClient(httpClient))
rpcClient, err := rpc.DialOptions(context.Background(), endpoint, rpc.WithHTTPClient(httpClient), rpc.WithHeaders(headers))
if err != nil {
return nil, err
}
Expand All @@ -79,7 +79,7 @@ func NewSignerClient(logger log.Logger, endpoint string, tlsConfig optls.CLIConf
}

func NewSignerClientFromConfig(logger log.Logger, config CLIConfig) (*SignerClient, error) {
return NewSignerClient(logger, config.Endpoint, config.TLSConfig)
return NewSignerClient(logger, config.Endpoint, config.Headers, config.TLSConfig)
}

func (s *SignerClient) pingVersion() (string, error) {
Expand Down
6 changes: 5 additions & 1 deletion op-service/tls/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@ type CLIConfig struct {
TLSCaCert string
TLSCert string
TLSKey string
Enabled bool
}

func NewCLIConfig() CLIConfig {
return CLIConfig{
TLSCaCert: defaultTLSCaCert,
TLSCert: defaultTLSCert,
TLSKey: defaultTLSKey,
Enabled: false,
}
}

Expand All @@ -83,7 +85,7 @@ func (c CLIConfig) Check() error {
}

func (c CLIConfig) TLSEnabled() bool {
return !(c.TLSCaCert == "" && c.TLSCert == "" && c.TLSKey == "")
return c.Enabled
}

// ReadCLIConfig reads tls cli configs
Expand All @@ -93,6 +95,7 @@ func ReadCLIConfig(ctx *cli.Context) CLIConfig {
TLSCaCert: ctx.String(TLSCaCertFlagName),
TLSCert: ctx.String(TLSCertFlagName),
TLSKey: ctx.String(TLSKeyFlagName),
Enabled: ctx.IsSet(TLSCaCertFlagName) || ctx.IsSet(TLSCertFlagName) || ctx.IsSet(TLSKeyFlagName),
}
}

Expand All @@ -106,5 +109,6 @@ func ReadCLIConfigWithPrefix(ctx *cli.Context, flagPrefix string) CLIConfig {
TLSCaCert: ctx.String(prefixFunc(TLSCaCertFlagName)),
TLSCert: ctx.String(prefixFunc(TLSCertFlagName)),
TLSKey: ctx.String(prefixFunc(TLSKeyFlagName)),
Enabled: ctx.IsSet(TLSCaCertFlagName) || ctx.IsSet(TLSCertFlagName) || ctx.IsSet(TLSKeyFlagName),
}
}
1 change: 1 addition & 0 deletions op-service/tls/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func TestInvalidConfig(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
cfg := NewCLIConfig()
cfg.Enabled = true
test.configChange(&cfg)
err := cfg.Check()
require.ErrorContains(t, err, "all tls flags must be set if at least one is set")
Expand Down

0 comments on commit be5b9c6

Please sign in to comment.