config: respect the user's security protocol preference order

This commit is contained in:
Marten Seemann 2022-11-20 20:01:56 +13:00
parent 6d3926394d
commit 1ecf340f51
3 changed files with 47 additions and 21 deletions

View File

@ -2,6 +2,7 @@ package config
import ( import (
"crypto/rand" "crypto/rand"
"errors"
"fmt" "fmt"
"time" "time"
@ -13,6 +14,7 @@ import (
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/core/peerstore"
"github.com/libp2p/go-libp2p/core/pnet" "github.com/libp2p/go-libp2p/core/pnet"
"github.com/libp2p/go-libp2p/core/protocol"
"github.com/libp2p/go-libp2p/core/routing" "github.com/libp2p/go-libp2p/core/routing"
"github.com/libp2p/go-libp2p/core/sec" "github.com/libp2p/go-libp2p/core/sec"
"github.com/libp2p/go-libp2p/core/sec/insecure" "github.com/libp2p/go-libp2p/core/sec/insecure"
@ -53,6 +55,11 @@ type AutoNATConfig struct {
ThrottleInterval time.Duration ThrottleInterval time.Duration
} }
type Security struct {
ID protocol.ID
Constructor interface{}
}
// Config describes a set of settings for a libp2p node // Config describes a set of settings for a libp2p node
// //
// This is *not* a stable interface. Use the options defined in the root // This is *not* a stable interface. Use the options defined in the root
@ -73,7 +80,7 @@ type Config struct {
Transports []fx.Option Transports []fx.Option
Muxers []tptu.StreamMuxer Muxers []tptu.StreamMuxer
SecurityTransports []fx.Option SecurityTransports []Security
Insecure bool Insecure bool
PSK pnet.PSK PSK pnet.PSK
@ -171,7 +178,7 @@ func (cfg *Config) addTransports(h host.Host) error {
fxopts := []fx.Option{ fxopts := []fx.Option{
fx.WithLogger(func() fxevent.Logger { return getFXLogger() }), fx.WithLogger(func() fxevent.Logger { return getFXLogger() }),
fx.Provide(fx.Annotate(tptu.New, fx.ParamTags(`group:"security"`))), fx.Provide(fx.Annotate(tptu.New, fx.ParamTags(`name:"security"`))),
fx.Supply(cfg.Muxers), fx.Supply(cfg.Muxers),
fx.Supply(h.ID()), fx.Supply(h.ID()),
fx.Provide(func() host.Host { return h }), fx.Provide(func() host.Host { return h }),
@ -194,7 +201,42 @@ func (cfg *Config) addTransports(h host.Host) error {
), ),
) )
} else { } else {
fxopts = append(fxopts, cfg.SecurityTransports...) // fx groups are unordered, but we need to preserve the order of the security transports
// First of all, we construct the security transports that are needed,
// and save them to a group call security_unordered.
for _, s := range cfg.SecurityTransports {
fxName := fmt.Sprintf(`name:"security_%s"`, s.ID)
fxopts = append(fxopts, fx.Supply(fx.Annotate(s.ID, fx.ResultTags(fxName))))
fxopts = append(fxopts,
fx.Provide(fx.Annotate(
s.Constructor,
fx.ParamTags(fxName),
fx.As(new(sec.SecureTransport)),
fx.ResultTags(`group:"security_unordered"`),
)),
)
}
// Then we consume the group security_unordered, and order them by the user's preference.
fxopts = append(fxopts, fx.Provide(
fx.Annotate(
func(secs []sec.SecureTransport) ([]sec.SecureTransport, error) {
if len(secs) != len(cfg.SecurityTransports) {
return nil, errors.New("inconsistent length for security transports")
}
t := make([]sec.SecureTransport, 0, len(secs))
for _, s := range cfg.SecurityTransports {
for _, st := range secs {
if s.ID != st.ID() {
continue
}
t = append(t, st)
}
}
return t, nil
},
fx.ParamTags(`group:"security_unordered"`),
fx.ResultTags(`name:"security"`),
)))
} }
fxopts = append(fxopts, fx.Invoke( fxopts = append(fxopts, fx.Invoke(

View File

@ -57,7 +57,7 @@ type ConnSecurity interface {
// RemotePublicKey returns the public key of the remote peer. // RemotePublicKey returns the public key of the remote peer.
RemotePublicKey() ic.PubKey RemotePublicKey() ic.PubKey
// Connection state info of the secured connection. // ConnState returns information about the connection state.
ConnState() ConnectionState ConnState() ConnectionState
} }

View File

@ -19,7 +19,6 @@ import (
"github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/core/peerstore"
"github.com/libp2p/go-libp2p/core/pnet" "github.com/libp2p/go-libp2p/core/pnet"
"github.com/libp2p/go-libp2p/core/protocol" "github.com/libp2p/go-libp2p/core/protocol"
"github.com/libp2p/go-libp2p/core/sec"
"github.com/libp2p/go-libp2p/core/transport" "github.com/libp2p/go-libp2p/core/transport"
"github.com/libp2p/go-libp2p/p2p/host/autorelay" "github.com/libp2p/go-libp2p/p2p/host/autorelay"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic" bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
@ -73,22 +72,7 @@ func Security(name string, constructor interface{}) Option {
if cfg.Insecure { if cfg.Insecure {
return fmt.Errorf("cannot use security transports with an insecure libp2p configuration") return fmt.Errorf("cannot use security transports with an insecure libp2p configuration")
} }
fxName := fmt.Sprintf(`name:"%s"`, name) cfg.SecurityTransports = append(cfg.SecurityTransports, config.Security{ID: protocol.ID(name), Constructor: constructor})
// provide the name of the security transport
cfg.SecurityTransports = append(cfg.SecurityTransports,
fx.Provide(fx.Annotate(
func() protocol.ID { return protocol.ID(name) },
fx.ResultTags(fxName),
)),
)
cfg.SecurityTransports = append(cfg.SecurityTransports,
fx.Provide(fx.Annotate(
constructor,
fx.ParamTags(fxName),
fx.As(new(sec.SecureTransport)),
fx.ResultTags(`group:"security"`),
)),
)
return nil return nil
} }
} }