Implement config generator

This commit adds code to allow the generation of a default client
configuration. The generator is run instead of the regular client
code, when the option -generate-config is passed on the command
line.
This commit is contained in:
Jan Dittberner 2022-12-03 12:22:00 +01:00
parent da24ae70b6
commit c65853d1f9
3 changed files with 87 additions and 40 deletions

View file

@ -20,9 +20,12 @@ package main
import (
"context"
"flag"
"fmt"
"os"
"strings"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
"git.cacert.org/cacert-gosigner/pkg/protocol"
"git.cacert.org/cacert-gosignerclient/internal/client"
@ -42,9 +45,9 @@ const (
func main() {
var (
showVersion, verbose bool
configFile, logLevel string
logger *logrus.Logger
showVersion, verbose, generateConfig bool
configFile, logLevel string
logger *logrus.Logger
)
logger = logrus.New()
@ -56,6 +59,12 @@ func main() {
flag.StringVar(&configFile, "config", defaultConfigFile, "signer client configuration file")
flag.BoolVar(&showVersion, "version", false, "show version")
flag.BoolVar(&verbose, "verbose", false, "verbose output")
flag.BoolVar(
&generateConfig,
"generate-config",
false,
"generate a configuration file with default values instead of running the client",
)
flag.StringVar(&logLevel, "loglevel", "INFO", "log level")
flag.Parse()
@ -71,9 +80,45 @@ func main() {
logger.SetLevel(parsedLevel)
if generateConfig {
if err = generateDefaultConfig(); err != nil {
logger.WithError(err).Fatal("could not generate default configuration")
}
return
}
if err := startClient(configFile, logger); err != nil {
logger.WithError(err).Fatal("client failure")
}
}
func generateDefaultConfig() error {
const defaultBaseConfiguration = `---
serial:
device: /dev/ttyUSB0
baud: 112500
`
cfg, err := config.LoadConfiguration(strings.NewReader(
defaultBaseConfiguration))
if err != nil {
return fmt.Errorf("could not load empty configuration: %w", err)
}
enc := yaml.NewEncoder(os.Stdout)
if err = enc.Encode(cfg); err != nil {
return fmt.Errorf("could not encode: %w", err)
}
return nil
}
func startClient(configFile string, logger *logrus.Logger) error {
clientConfig, err := config.New(configFile)
if err != nil {
logger.WithError(err).Fatal("could not configure client")
return fmt.Errorf("could not configure client: %w", err)
}
commands := make(chan *protocol.Command)
@ -81,12 +126,12 @@ func main() {
clientHandler, err := handler.New(clientConfig, logger, commands, callbacks)
if err != nil {
logger.WithError(err).Fatal("could not setup client handler")
return fmt.Errorf("could not setup client handler: %w", err)
}
signerClient, err := client.New(clientConfig, logger, clientHandler, commands, callbacks)
if err != nil {
logger.WithError(err).Fatal("could not setup client")
return fmt.Errorf("could not setup client: %w", err)
}
defer func() { _ = signerClient.Close() }()
@ -94,6 +139,8 @@ func main() {
logger.Info("setup complete, starting client operation")
if err = signerClient.Run(context.Background()); err != nil {
logger.WithError(err).Fatal("error in client")
return fmt.Errorf("error in client: %w", err)
}
return nil
}

View file

@ -432,24 +432,16 @@ func (c *Client) updateCRL(d *messages.FetchCRLResponse) ([]*protocol.Command, e
}
func (c *Client) buildCRLFileName(caName string) string {
return path.Join(c.config.PublicDataDirectory, fmt.Sprintf("%s.crl", caName))
return path.Join(c.config.PublicCRLDirectory, fmt.Sprintf("%s.crl", caName))
}
func (c *Client) buildCertificateFileName(caName string, certFormat string) string {
return path.Join(c.config.PublicDataDirectory, fmt.Sprintf("%s.%s", caName, certFormat))
}
func (c *Client) ensurePublicDataDirectory() error {
if err := os.MkdirAll(c.config.PublicDataDirectory, worldReadableDirPerm); err != nil {
return fmt.Errorf("could not create public CA data directory %s: %w", c.config.PublicDataDirectory, err)
}
return nil
return path.Join(c.config.PublicCRLDirectory, fmt.Sprintf("%s.%s", caName, certFormat))
}
func (c *Client) writeCertificate(caName string, derBytes []byte) error {
if err := c.ensurePublicDataDirectory(); err != nil {
return err
if err := os.MkdirAll(c.config.PublicCRLDirectory, worldReadableDirPerm); err != nil {
return fmt.Errorf("could not create public CA data directory %s: %w", c.config.PublicCRLDirectory, err)
}
if err := os.WriteFile(
@ -470,8 +462,8 @@ func (c *Client) writeCertificate(caName string, derBytes []byte) error {
}
func (c *Client) writeCRL(caName string, crlBytes []byte) error {
if err := c.ensurePublicDataDirectory(); err != nil {
return err
if err := os.MkdirAll(c.config.PublicCRLDirectory, worldReadableDirPerm); err != nil {
return fmt.Errorf("could not create public CA data directory %s: %w", c.config.PublicCRLDirectory, err)
}
if err := os.WriteFile(c.buildCRLFileName(caName), crlBytes, worldReadableFilePerm); err != nil {

View file

@ -52,26 +52,28 @@ type Serial struct {
}
type ClientConfig struct {
Serial Serial `yaml:"serial"`
HealthInterval time.Duration `yaml:"health-interval"`
HealthStart time.Duration `yaml:"health-start"`
FetchCRLStart time.Duration `yaml:"fetch-crl-start"`
FetchCRLInterval time.Duration `yaml:"fetch-crl-interval"`
ResponseAnnounceTimeout time.Duration `yaml:"response-announce-timeout"`
ResponseDataTimeout time.Duration `yaml:"response-data-timeout"`
PublicDataDirectory string `yaml:"public-data-directory"`
Serial Serial `yaml:"serial"`
HealthInterval time.Duration `yaml:"health-interval"`
HealthStart time.Duration `yaml:"health-start"`
FetchCRLStart time.Duration `yaml:"fetch-crl-start"`
FetchCRLInterval time.Duration `yaml:"fetch-crl-interval"`
ResponseAnnounceTimeout time.Duration `yaml:"response-announce-timeout"`
ResponseDataTimeout time.Duration `yaml:"response-data-timeout"`
PublicCRLDirectory string `yaml:"public-crl-directory"`
PublicCertificateDirectory string `yaml:"public-certificate-directory"`
}
func (c *ClientConfig) UnmarshalYAML(n *yaml.Node) error {
data := struct {
Serial Serial `yaml:"serial"`
HealthInterval time.Duration `yaml:"health-interval"`
HealthStart time.Duration `yaml:"health-start"`
FetchCRLStart time.Duration `yaml:"fetch-crl-start"`
FetchCRLInterval time.Duration `yaml:"fetch-crl-interval"`
ResponseAnnounceTimeout time.Duration `yaml:"response-announce-timeout"`
ResponseDataTimeout time.Duration `yaml:"response-data-timeout"`
PublicDataDirectory string `yaml:"public-data-directory"`
Serial Serial `yaml:"serial"`
HealthInterval time.Duration `yaml:"health-interval"`
HealthStart time.Duration `yaml:"health-start"`
FetchCRLStart time.Duration `yaml:"fetch-crl-start"`
FetchCRLInterval time.Duration `yaml:"fetch-crl-interval"`
ResponseAnnounceTimeout time.Duration `yaml:"response-announce-timeout"`
ResponseDataTimeout time.Duration `yaml:"response-data-timeout"`
PublicCRLDirectory string `yaml:"public-crl-directory"`
PublicCertificateDirectory string `yaml:"public-certificate-directory"`
}{}
err := n.Decode(&data)
@ -129,11 +131,17 @@ func (c *ClientConfig) UnmarshalYAML(n *yaml.Node) error {
c.ResponseDataTimeout = data.ResponseDataTimeout
if data.PublicDataDirectory == "" {
data.PublicDataDirectory = defaultFilesDirectory
if data.PublicCRLDirectory == "" {
data.PublicCRLDirectory = defaultFilesDirectory
}
c.PublicDataDirectory = data.PublicDataDirectory
c.PublicCRLDirectory = data.PublicCRLDirectory
if data.PublicCertificateDirectory == "" {
data.PublicCertificateDirectory = defaultFilesDirectory
}
c.PublicCertificateDirectory = data.PublicCRLDirectory
return nil
}