certificates/sshutil/options.go
Mariano Cano df1f7e5a2e Use CertificateRequest type as input for ssh NewCertificate.
SSH does not have a real concept of ssh certificate request, but
we are using the type to encapsulate the parameters coming in the
request.
2020-07-30 17:45:03 -07:00

90 lines
2.3 KiB
Go

package sshutil
import (
"bytes"
"encoding/base64"
"io/ioutil"
"text/template"
"github.com/Masterminds/sprig/v3"
"github.com/pkg/errors"
"github.com/smallstep/cli/config"
)
func getFuncMap(failMessage *string) template.FuncMap {
m := sprig.TxtFuncMap()
m["fail"] = func(msg string) (string, error) {
*failMessage = msg
return "", errors.New(msg)
}
return m
}
// Options are the options that can be passed to NewCertificate.
type Options struct {
CertBuffer *bytes.Buffer
}
func (o *Options) apply(cr CertificateRequest, opts []Option) (*Options, error) {
for _, fn := range opts {
if err := fn(cr, o); err != nil {
return o, err
}
}
return o, nil
}
// Option is the type used as a variadic argument in NewCertificate.
type Option func(cr CertificateRequest, o *Options) error
// WithTemplate is an options that executes the given template text with the
// given data.
func WithTemplate(text string, data TemplateData) Option {
return func(cr CertificateRequest, o *Options) error {
terr := new(TemplateError)
funcMap := getFuncMap(&terr.Message)
tmpl, err := template.New("template").Funcs(funcMap).Parse(text)
if err != nil {
return errors.Wrapf(err, "error parsing template")
}
buf := new(bytes.Buffer)
data.SetCertificateRequest(cr)
if err := tmpl.Execute(buf, data); err != nil {
if terr.Message != "" {
return terr
}
return errors.Wrapf(err, "error executing template")
}
o.CertBuffer = buf
return nil
}
}
// WithTemplateBase64 is an options that executes the given template base64
// string with the given data.
func WithTemplateBase64(s string, data TemplateData) Option {
return func(cr CertificateRequest, o *Options) error {
b, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return errors.Wrap(err, "error decoding template")
}
fn := WithTemplate(string(b), data)
return fn(cr, o)
}
}
// WithTemplateFile is an options that reads the template file and executes it
// with the given data.
func WithTemplateFile(path string, data TemplateData) Option {
return func(cr CertificateRequest, o *Options) error {
filename := config.StepAbs(path)
b, err := ioutil.ReadFile(filename)
if err != nil {
return errors.Wrapf(err, "error reading %s", path)
}
fn := WithTemplate(string(b), data)
return fn(cr, o)
}
}