78 lines
2.4 KiB
Go
78 lines
2.4 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"time"
|
|
|
|
dmcrypto "git.clan.lol/clan/data-mesher/pkg/crypto"
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
)
|
|
|
|
// MinPushPullInterval specifies the minimum interval between push-pull operations in seconds.
|
|
const MinPushPullInterval = 5 * time.Second
|
|
|
|
// Cluster represents the configuration for a cluster using libp2p.
|
|
type Cluster struct {
|
|
Port uint16 `mapstructure:"port"`
|
|
Interfaces []string `mapstructure:"interfaces"`
|
|
|
|
BootstrapPeers []peer.AddrInfo `mapstructure:"bootstrap_peers"`
|
|
PushPullInterval time.Duration `mapstructure:"push_pull_interval"`
|
|
|
|
// Certificate-based authentication
|
|
IdentityKey *dmcrypto.PrivateKey `mapstructure:"identity_key"`
|
|
IdentityCert *dmcrypto.Certificate `mapstructure:"identity_cert"`
|
|
}
|
|
|
|
// Validate checks the cluster configuration for valid values.
|
|
func (c *Cluster) Validate(network *dmcrypto.PublicKey) error {
|
|
if c.Port == 0 {
|
|
return fmt.Errorf("%w: cluster port must be between 1 and 65535", ErrInvalidConfig)
|
|
}
|
|
|
|
if len(c.BootstrapPeers) == 0 {
|
|
return fmt.Errorf("%w: at least one bootstrap peer is required", ErrInvalidConfig)
|
|
}
|
|
|
|
// we don't want push/pull to happen too frequently
|
|
if c.PushPullInterval < MinPushPullInterval {
|
|
return fmt.Errorf("%w: cluster push pull interval must be >= %v seconds", ErrInvalidConfig, MinPushPullInterval)
|
|
}
|
|
|
|
if c.IdentityKey == nil {
|
|
return fmt.Errorf("%w: identity key is required", ErrInvalidConfig)
|
|
}
|
|
|
|
peerID, err := c.IdentityKey.PeerID()
|
|
if err != nil {
|
|
// this shouldn't really happen
|
|
return fmt.Errorf("%w: failed to derive peer ID from identity key", ErrInvalidConfig)
|
|
}
|
|
|
|
if c.IdentityCert == nil {
|
|
return fmt.Errorf("%w: identity certificate is required", ErrInvalidConfig)
|
|
}
|
|
|
|
// verify the certificate's public key matches the identity key
|
|
if !c.IdentityCert.IdentityKey.Equal(c.IdentityKey.Public) {
|
|
return fmt.Errorf("%w: identity certificate public key does not match identity key", ErrInvalidConfig)
|
|
}
|
|
|
|
// verify the certificate is signed by this node's home network
|
|
if err = c.IdentityCert.Verify(network); err != nil {
|
|
return fmt.Errorf("%w: identity certificate not signed by network certificate authority", ErrInvalidConfig)
|
|
}
|
|
|
|
slog.Debug(
|
|
"cluster config",
|
|
"port", c.Port,
|
|
"interfaces", c.Interfaces,
|
|
"bootstrap_peers", c.BootstrapPeers,
|
|
"push_pull_interval", c.PushPullInterval,
|
|
"peer_id", peerID,
|
|
)
|
|
|
|
return nil
|
|
}
|