2020-07-01 02:19:52 +00:00
|
|
|
package x509util
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2020-07-09 18:40:37 +00:00
|
|
|
"crypto/x509"
|
2020-07-15 00:12:07 +00:00
|
|
|
"encoding/base64"
|
2020-07-01 02:19:52 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"text/template"
|
|
|
|
|
2020-07-08 02:09:29 +00:00
|
|
|
"github.com/Masterminds/sprig/v3"
|
2020-07-01 02:19:52 +00:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/smallstep/cli/config"
|
|
|
|
)
|
|
|
|
|
2020-07-16 19:25:40 +00:00
|
|
|
func getFuncMap(failMessage *string) template.FuncMap {
|
|
|
|
m := sprig.TxtFuncMap()
|
|
|
|
m["fail"] = func(msg string) (string, error) {
|
|
|
|
*failMessage = msg
|
|
|
|
return "", errors.New(msg)
|
|
|
|
}
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
2020-07-08 01:59:18 +00:00
|
|
|
// Options are the options that can be passed to NewCertificate.
|
2020-07-01 02:19:52 +00:00
|
|
|
type Options struct {
|
|
|
|
CertBuffer *bytes.Buffer
|
|
|
|
}
|
|
|
|
|
2020-07-09 18:40:37 +00:00
|
|
|
func (o *Options) apply(cr *x509.CertificateRequest, opts []Option) (*Options, error) {
|
2020-07-01 02:19:52 +00:00
|
|
|
for _, fn := range opts {
|
2020-07-09 18:40:37 +00:00
|
|
|
if err := fn(cr, o); err != nil {
|
2020-07-01 02:19:52 +00:00
|
|
|
return o, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return o, nil
|
|
|
|
}
|
|
|
|
|
2020-07-08 01:59:18 +00:00
|
|
|
// Option is the type used as a variadic argument in NewCertificate.
|
2020-07-09 18:40:37 +00:00
|
|
|
type Option func(cr *x509.CertificateRequest, o *Options) error
|
2020-07-01 02:19:52 +00:00
|
|
|
|
2020-07-08 01:59:18 +00:00
|
|
|
// WithTemplate is an options that executes the given template text with the
|
|
|
|
// given data.
|
2020-07-09 18:40:37 +00:00
|
|
|
func WithTemplate(text string, data TemplateData) Option {
|
|
|
|
return func(cr *x509.CertificateRequest, o *Options) error {
|
2020-07-16 19:25:40 +00:00
|
|
|
terr := new(TemplateError)
|
|
|
|
funcMap := getFuncMap(&terr.Message)
|
|
|
|
|
|
|
|
tmpl, err := template.New("template").Funcs(funcMap).Parse(text)
|
2020-07-02 01:30:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "error parsing template")
|
|
|
|
}
|
|
|
|
|
|
|
|
buf := new(bytes.Buffer)
|
2020-07-09 18:40:37 +00:00
|
|
|
data.SetCertificateRequest(cr)
|
2020-07-02 01:30:04 +00:00
|
|
|
if err := tmpl.Execute(buf, data); err != nil {
|
2020-07-16 19:25:40 +00:00
|
|
|
if terr.Message != "" {
|
|
|
|
return terr
|
|
|
|
}
|
2020-07-02 01:30:04 +00:00
|
|
|
return errors.Wrapf(err, "error executing template")
|
|
|
|
}
|
|
|
|
o.CertBuffer = buf
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-15 00:12:07 +00:00
|
|
|
// 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 *x509.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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-08 01:59:18 +00:00
|
|
|
// WithTemplateFile is an options that reads the template file and executes it
|
|
|
|
// with the given data.
|
2020-07-09 18:40:37 +00:00
|
|
|
func WithTemplateFile(path string, data TemplateData) Option {
|
|
|
|
return func(cr *x509.CertificateRequest, o *Options) error {
|
2020-07-01 02:19:52 +00:00
|
|
|
filename := config.StepAbs(path)
|
|
|
|
b, err := ioutil.ReadFile(filename)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "error reading %s", path)
|
|
|
|
}
|
2020-07-15 00:12:07 +00:00
|
|
|
fn := WithTemplate(string(b), data)
|
|
|
|
return fn(cr, o)
|
2020-07-01 02:19:52 +00:00
|
|
|
}
|
|
|
|
}
|