ecadlabs/signatory

View on GitHub
cmd/commands/root.go

Summary

Maintainability
B
6 hrs
Test Coverage
D
68%
package commands

import (
    "context"
    "os"
    "strings"

    "github.com/ecadlabs/signatory/pkg/auth"
    "github.com/ecadlabs/signatory/pkg/config"
    "github.com/ecadlabs/signatory/pkg/metrics"
    "github.com/ecadlabs/signatory/pkg/signatory"
    log "github.com/sirupsen/logrus"
    "github.com/spf13/cobra"
)

// Context represents root command context shared with its children
type Context struct {
    Context context.Context

    config    *config.Config
    signatory *signatory.Signatory
}

// NewRootCommand returns new root command
func NewRootCommand(c *Context, name string) *cobra.Command {
    var (
        level      string
        configFile string
        baseDir    string
        jsonLog    bool
    )

    rootCmd := cobra.Command{
        Use:   name,
        Short: "A Tezos Remote Signer for signing block-chain operations with private keys",
        PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
            if cmd.Use == "version" ||
                strings.Contains(cmd.CommandPath(), "ledger") ||
                strings.Contains(cmd.CommandPath(), "list-requests") ||
                strings.Contains(cmd.CommandPath(), "list-ops") {
                return nil
            }

            // cmd always points to the top level command!!!
            conf := config.Default()
            if configFile != "" {
                if err := conf.Read(configFile); err != nil {
                    return err
                }
            }

            if baseDir == "" {
                baseDir = conf.BaseDir
            }
            baseDir = os.ExpandEnv(baseDir)
            if err := os.MkdirAll(baseDir, 0770); err != nil {
                return err
            }

            validate := config.Validator()
            if err := validate.Struct(conf); err != nil {
                return err
            }

            if jsonLog {
                log.SetFormatter(&log.JSONFormatter{})
            }

            lv, err := log.ParseLevel(level)
            if err != nil {
                return err
            }

            log.SetLevel(lv)

            pol, err := signatory.PreparePolicy(conf.Tezos)
            if err != nil {
                return err
            }

            watermark, err := signatory.NewFileWatermark(baseDir)
            if err != nil {
                return err
            }

            sigConf := signatory.Config{
                Policy:      pol,
                Vaults:      conf.Vaults,
                Interceptor: metrics.Interceptor,
                Watermark:   watermark,
            }

            if conf.PolicyHook != nil && conf.PolicyHook.Address != "" {
                sigConf.PolicyHook = &signatory.PolicyHook{
                    Address: conf.PolicyHook.Address,
                }
                if conf.PolicyHook.AuthorizedKeys != nil {
                    ak, err := auth.StaticAuthorizedKeys(conf.PolicyHook.AuthorizedKeys.List()...)
                    if err != nil {
                        return err
                    }
                    sigConf.PolicyHook.Auth = ak
                }
            }

            sig, err := signatory.New(c.Context, &sigConf)
            if err != nil {
                return err
            }

            if err = sig.Unlock(c.Context); err != nil {
                return err
            }

            c.config = conf
            c.signatory = sig
            return nil
        },
    }

    f := rootCmd.PersistentFlags()

    f.StringVarP(&configFile, "config", "c", "/etc/signatory.yaml", "Config file path")
    f.StringVar(&level, "log", "info", "Log level: [error, warn, info, debug, trace]")
    f.StringVar(&baseDir, "base-dir", "", "Base directory. Takes priority over one specified in config")
    f.BoolVar(&jsonLog, "json-log", false, "Use JSON structured logs")

    return &rootCmd
}