Jan Dittberner
f3c0e1379f
- Rename client.CertInfo to CACertificateInfo - declare commands channel inside client.Run, there is no need to inject it from the outside - let command generating code in client.commandLoop run in goroutines to allow parallel handling of queued commands and avoid blocking operations - pass context to command generating functions to allow cancellation - guard access to c.knownCACertificates by mutex.Lock and mutex.Unlock - make command channel capacity configurable - update to latest cacert-gosigner dependency for channel direction support - improve handling of closed input channel - reduce client initialization to serial connection setup, move callback and handler parameters to client.Run invocation
172 lines
3.8 KiB
Go
172 lines
3.8 KiB
Go
/*
|
|
Copyright 2022 CAcert Inc.
|
|
SPDX-License-Identifier: Apache-2.0
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"git.cacert.org/cacert-gosignerclient/internal/client"
|
|
"git.cacert.org/cacert-gosignerclient/internal/config"
|
|
"git.cacert.org/cacert-gosignerclient/internal/handler"
|
|
)
|
|
|
|
var (
|
|
commit = "dev"
|
|
date = "unknown"
|
|
version = "unknown"
|
|
)
|
|
|
|
const (
|
|
defaultConfigFile = "config.yaml"
|
|
)
|
|
|
|
func main() {
|
|
var (
|
|
showVersion, verbose, generateConfig bool
|
|
configFile, logLevel string
|
|
logger *logrus.Logger
|
|
)
|
|
|
|
logger = logrus.New()
|
|
logger.SetOutput(os.Stdout)
|
|
logger.SetLevel(logrus.InfoLevel)
|
|
|
|
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()
|
|
|
|
parsedLevel, err := logrus.ParseLevel(logLevel)
|
|
if err != nil {
|
|
logger.WithError(err).Fatal("could not parse log level")
|
|
}
|
|
|
|
if generateConfig {
|
|
if err = generateDefaultConfig(); err != nil {
|
|
logger.WithError(err).Fatal("could not generate default configuration")
|
|
}
|
|
|
|
os.Exit(1)
|
|
}
|
|
|
|
logger.Infof("cacert-gosignerclient %s (%s) - build %s", version, commit, date)
|
|
|
|
if showVersion {
|
|
return
|
|
}
|
|
|
|
logger.SetLevel(parsedLevel)
|
|
|
|
if err := startClient(configFile, logger); err != nil {
|
|
logger.WithError(err).Error("client failure")
|
|
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
buf := &bytes.Buffer{}
|
|
|
|
buf.WriteString("---\n")
|
|
|
|
enc := yaml.NewEncoder(buf)
|
|
|
|
if err = enc.Encode(cfg); err != nil {
|
|
return fmt.Errorf("could not encode: %w", err)
|
|
}
|
|
|
|
_, err = io.Copy(os.Stdout, buf)
|
|
if err != nil {
|
|
return fmt.Errorf("could not write output: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func startClient(configFile string, logger *logrus.Logger) error {
|
|
clientConfig, err := config.New(configFile)
|
|
if err != nil {
|
|
return fmt.Errorf("could not configure client: %w", err)
|
|
}
|
|
|
|
signerClient, err := client.New(clientConfig, logger)
|
|
if err != nil {
|
|
return fmt.Errorf("could not setup client: %w", err)
|
|
}
|
|
|
|
defer func() { _ = signerClient.Close() }()
|
|
|
|
logger.Info("setup complete, starting client operation")
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
c := make(chan os.Signal, 1)
|
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
|
|
|
go func() {
|
|
<-c
|
|
|
|
logger.Info("received shutdown signal")
|
|
|
|
cancel()
|
|
}()
|
|
|
|
callbacks := make(chan interface{}, client.CallBackBufferSize)
|
|
|
|
clientHandler, err := handler.New(clientConfig, logger, callbacks)
|
|
if err != nil {
|
|
return fmt.Errorf("could not setup client handler: %w", err)
|
|
}
|
|
|
|
if err = signerClient.Run(ctx, callbacks, clientHandler); err != nil {
|
|
return fmt.Errorf("error in client: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|