From 8f0dd811afa57d671a98c972ec4eb69d58e9c870 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Thu, 16 Jul 2020 12:25:40 -0700 Subject: [PATCH] Allow to send errors from template to cli. --- authority/tls.go | 3 +++ x509util/options.go | 17 ++++++++++++++++- x509util/templates.go | 8 ++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/authority/tls.go b/authority/tls.go index 463c84b3..280e45b6 100644 --- a/authority/tls.go +++ b/authority/tls.go @@ -108,6 +108,9 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Opti cert, err := x509cert.NewCertificate(csr, certOptions...) if err != nil { + if _, ok := err.(*x509cert.TemplateError); ok { + return nil, errs.NewErr(http.StatusBadRequest, err, errs.WithMessage(err.Error())) + } return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.Sign", opts...) } diff --git a/x509util/options.go b/x509util/options.go index 6b2b8697..510ce972 100644 --- a/x509util/options.go +++ b/x509util/options.go @@ -12,6 +12,15 @@ import ( "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 @@ -33,7 +42,10 @@ type Option func(cr *x509.CertificateRequest, o *Options) error // given data. func WithTemplate(text string, data TemplateData) Option { return func(cr *x509.CertificateRequest, o *Options) error { - tmpl, err := template.New("template").Funcs(sprig.TxtFuncMap()).Parse(text) + 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") } @@ -41,6 +53,9 @@ func WithTemplate(text string, data TemplateData) Option { 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 diff --git a/x509util/templates.go b/x509util/templates.go index 33b05c10..84e48e0c 100644 --- a/x509util/templates.go +++ b/x509util/templates.go @@ -13,6 +13,14 @@ const ( CertificateRequestKey = "CR" ) +type TemplateError struct { + Message string +} + +func (e *TemplateError) Error() string { + return e.Message +} + // TemplateData is an alias for map[string]interface{}. It represents the data // passed to the templates. type TemplateData map[string]interface{}