Commit 12225341 authored by Joshua Gutow's avatar Joshua Gutow Committed by GitHub

op-service: Add optional headers to the signer client (#12407)

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

* Explain flag usage
parent bb2c99c8
...@@ -2,6 +2,8 @@ package signer ...@@ -2,6 +2,8 @@ package signer
import ( import (
"errors" "errors"
"net/http"
"strings"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
...@@ -12,6 +14,7 @@ import ( ...@@ -12,6 +14,7 @@ import (
const ( const (
EndpointFlagName = "signer.endpoint" EndpointFlagName = "signer.endpoint"
AddressFlagName = "signer.address" AddressFlagName = "signer.address"
HeadersFlagName = "signer.header"
) )
func CLIFlags(envPrefix string) []cli.Flag { func CLIFlags(envPrefix string) []cli.Flag {
...@@ -27,6 +30,11 @@ func CLIFlags(envPrefix string) []cli.Flag { ...@@ -27,6 +30,11 @@ func CLIFlags(envPrefix string) []cli.Flag {
Usage: "Address the signer is signing transactions for", Usage: "Address the signer is signing transactions for",
EnvVars: opservice.PrefixEnvVar(envPrefix, "ADDRESS"), 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")...) flags = append(flags, optls.CLIFlagsWithFlagPrefix(envPrefix, "signer")...)
return flags return flags
...@@ -35,11 +43,13 @@ func CLIFlags(envPrefix string) []cli.Flag { ...@@ -35,11 +43,13 @@ func CLIFlags(envPrefix string) []cli.Flag {
type CLIConfig struct { type CLIConfig struct {
Endpoint string Endpoint string
Address string Address string
Headers http.Header
TLSConfig optls.CLIConfig TLSConfig optls.CLIConfig
} }
func NewCLIConfig() CLIConfig { func NewCLIConfig() CLIConfig {
return CLIConfig{ return CLIConfig{
Headers: http.Header{},
TLSConfig: optls.NewCLIConfig(), TLSConfig: optls.NewCLIConfig(),
} }
} }
...@@ -62,9 +72,20 @@ func (c CLIConfig) Enabled() bool { ...@@ -62,9 +72,20 @@ func (c CLIConfig) Enabled() bool {
} }
func ReadCLIConfig(ctx *cli.Context) CLIConfig { 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{ cfg := CLIConfig{
Endpoint: ctx.String(EndpointFlagName), Endpoint: ctx.String(EndpointFlagName),
Address: ctx.String(AddressFlagName), Address: ctx.String(AddressFlagName),
Headers: headers,
TLSConfig: optls.ReadCLIConfigWithPrefix(ctx, "signer"), TLSConfig: optls.ReadCLIConfigWithPrefix(ctx, "signer"),
} }
return cfg return cfg
......
package signer package signer
import ( import (
"net/http"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -18,6 +19,37 @@ func TestDefaultConfigIsValid(t *testing.T) { ...@@ -18,6 +19,37 @@ func TestDefaultConfigIsValid(t *testing.T) {
require.NoError(t, err) 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) { func TestInvalidConfig(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
...@@ -29,6 +61,7 @@ func TestInvalidConfig(t *testing.T) { ...@@ -29,6 +61,7 @@ func TestInvalidConfig(t *testing.T) {
expected: "signer endpoint and address must both be set or not set", expected: "signer endpoint and address must both be set or not set",
configChange: func(config *CLIConfig) { configChange: func(config *CLIConfig) {
config.Address = "0x1234" config.Address = "0x1234"
config.TLSConfig.Enabled = true
}, },
}, },
{ {
...@@ -36,6 +69,7 @@ func TestInvalidConfig(t *testing.T) { ...@@ -36,6 +69,7 @@ func TestInvalidConfig(t *testing.T) {
expected: "signer endpoint and address must both be set or not set", expected: "signer endpoint and address must both be set or not set",
configChange: func(config *CLIConfig) { configChange: func(config *CLIConfig) {
config.Endpoint = "http://localhost" config.Endpoint = "http://localhost"
config.TLSConfig.Enabled = true
}, },
}, },
{ {
...@@ -43,6 +77,7 @@ func TestInvalidConfig(t *testing.T) { ...@@ -43,6 +77,7 @@ func TestInvalidConfig(t *testing.T) {
expected: "all tls flags must be set if at least one is set", expected: "all tls flags must be set if at least one is set",
configChange: func(config *CLIConfig) { configChange: func(config *CLIConfig) {
config.TLSConfig.TLSKey = "" config.TLSConfig.TLSKey = ""
config.TLSConfig.Enabled = true
}, },
}, },
} }
......
...@@ -25,9 +25,9 @@ type SignerClient struct { ...@@ -25,9 +25,9 @@ type SignerClient struct {
logger log.Logger 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 var httpClient *http.Client
if tlsConfig.TLSCaCert != "" { if tlsConfig.Enabled {
logger.Info("tlsConfig specified, loading tls config") logger.Info("tlsConfig specified, loading tls config")
caCert, err := os.ReadFile(tlsConfig.TLSCaCert) caCert, err := os.ReadFile(tlsConfig.TLSCaCert)
if err != nil { if err != nil {
...@@ -63,7 +63,7 @@ func NewSignerClient(logger log.Logger, endpoint string, tlsConfig optls.CLIConf ...@@ -63,7 +63,7 @@ func NewSignerClient(logger log.Logger, endpoint string, tlsConfig optls.CLIConf
httpClient = http.DefaultClient 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 { if err != nil {
return nil, err return nil, err
} }
...@@ -79,7 +79,7 @@ func NewSignerClient(logger log.Logger, endpoint string, tlsConfig optls.CLIConf ...@@ -79,7 +79,7 @@ func NewSignerClient(logger log.Logger, endpoint string, tlsConfig optls.CLIConf
} }
func NewSignerClientFromConfig(logger log.Logger, config CLIConfig) (*SignerClient, error) { 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) { func (s *SignerClient) pingVersion() (string, error) {
......
...@@ -64,6 +64,7 @@ type CLIConfig struct { ...@@ -64,6 +64,7 @@ type CLIConfig struct {
TLSCaCert string TLSCaCert string
TLSCert string TLSCert string
TLSKey string TLSKey string
Enabled bool
} }
func NewCLIConfig() CLIConfig { func NewCLIConfig() CLIConfig {
...@@ -71,6 +72,7 @@ func NewCLIConfig() CLIConfig { ...@@ -71,6 +72,7 @@ func NewCLIConfig() CLIConfig {
TLSCaCert: defaultTLSCaCert, TLSCaCert: defaultTLSCaCert,
TLSCert: defaultTLSCert, TLSCert: defaultTLSCert,
TLSKey: defaultTLSKey, TLSKey: defaultTLSKey,
Enabled: false,
} }
} }
...@@ -83,7 +85,7 @@ func (c CLIConfig) Check() error { ...@@ -83,7 +85,7 @@ func (c CLIConfig) Check() error {
} }
func (c CLIConfig) TLSEnabled() bool { func (c CLIConfig) TLSEnabled() bool {
return !(c.TLSCaCert == "" && c.TLSCert == "" && c.TLSKey == "") return c.Enabled
} }
// ReadCLIConfig reads tls cli configs // ReadCLIConfig reads tls cli configs
...@@ -93,6 +95,7 @@ func ReadCLIConfig(ctx *cli.Context) CLIConfig { ...@@ -93,6 +95,7 @@ func ReadCLIConfig(ctx *cli.Context) CLIConfig {
TLSCaCert: ctx.String(TLSCaCertFlagName), TLSCaCert: ctx.String(TLSCaCertFlagName),
TLSCert: ctx.String(TLSCertFlagName), TLSCert: ctx.String(TLSCertFlagName),
TLSKey: ctx.String(TLSKeyFlagName), TLSKey: ctx.String(TLSKeyFlagName),
Enabled: ctx.IsSet(TLSCaCertFlagName) || ctx.IsSet(TLSCertFlagName) || ctx.IsSet(TLSKeyFlagName),
} }
} }
...@@ -106,5 +109,6 @@ func ReadCLIConfigWithPrefix(ctx *cli.Context, flagPrefix string) CLIConfig { ...@@ -106,5 +109,6 @@ func ReadCLIConfigWithPrefix(ctx *cli.Context, flagPrefix string) CLIConfig {
TLSCaCert: ctx.String(prefixFunc(TLSCaCertFlagName)), TLSCaCert: ctx.String(prefixFunc(TLSCaCertFlagName)),
TLSCert: ctx.String(prefixFunc(TLSCertFlagName)), TLSCert: ctx.String(prefixFunc(TLSCertFlagName)),
TLSKey: ctx.String(prefixFunc(TLSKeyFlagName)), TLSKey: ctx.String(prefixFunc(TLSKeyFlagName)),
Enabled: ctx.IsSet(TLSCaCertFlagName) || ctx.IsSet(TLSCertFlagName) || ctx.IsSet(TLSKeyFlagName),
} }
} }
...@@ -36,6 +36,7 @@ func TestInvalidConfig(t *testing.T) { ...@@ -36,6 +36,7 @@ func TestInvalidConfig(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
cfg := NewCLIConfig() cfg := NewCLIConfig()
cfg.Enabled = true
test.configChange(&cfg) test.configChange(&cfg)
err := cfg.Check() err := cfg.Check()
require.ErrorContains(t, err, "all tls flags must be set if at least one is set") require.ErrorContains(t, err, "all tls flags must be set if at least one is set")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment