mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			156 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			156 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) HashiCorp, Inc.
 | 
						|
// SPDX-License-Identifier: MPL-2.0
 | 
						|
 | 
						|
package template
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"strings"
 | 
						|
	"text/template"
 | 
						|
 | 
						|
	"github.com/hashicorp/go-multierror"
 | 
						|
	"github.com/hashicorp/go-secure-stdlib/base62"
 | 
						|
)
 | 
						|
 | 
						|
type Opt func(*StringTemplate) error
 | 
						|
 | 
						|
func Template(rawTemplate string) Opt {
 | 
						|
	return func(up *StringTemplate) error {
 | 
						|
		up.rawTemplate = rawTemplate
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Function allows the user to specify functions for use in the template. If the name provided is a function that
 | 
						|
// already exists in the function map, this will override the previously specified function.
 | 
						|
func Function(name string, f interface{}) Opt {
 | 
						|
	return func(up *StringTemplate) error {
 | 
						|
		if name == "" {
 | 
						|
			return fmt.Errorf("missing function name")
 | 
						|
		}
 | 
						|
		if f == nil {
 | 
						|
			return fmt.Errorf("missing function")
 | 
						|
		}
 | 
						|
		up.funcMap[name] = f
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// StringTemplate creates strings based on the provided template.
 | 
						|
// This uses the go templating language, so anything that adheres to that language will function in this struct.
 | 
						|
// There are several custom functions available for use in the template:
 | 
						|
// - random
 | 
						|
//   - Randomly generated characters. This uses the charset specified in RandomCharset. Must include a length.
 | 
						|
//     Example: {{ rand 20 }}
 | 
						|
//
 | 
						|
// - truncate
 | 
						|
//   - Truncates the previous value to the specified length. Must include a maximum length.
 | 
						|
//     Example: {{ .DisplayName | truncate 10 }}
 | 
						|
//
 | 
						|
// - truncate_sha256
 | 
						|
//   - Truncates the previous value to the specified length. If the original length is greater than the length
 | 
						|
//     specified, the remaining characters will be sha256 hashed and appended to the end. The hash will be only the first 8 characters The maximum length will
 | 
						|
//     be no longer than the length specified.
 | 
						|
//     Example: {{ .DisplayName | truncate_sha256 30 }}
 | 
						|
//
 | 
						|
// - uppercase
 | 
						|
//   - Uppercases the previous value.
 | 
						|
//     Example: {{ .RoleName | uppercase }}
 | 
						|
//
 | 
						|
// - lowercase
 | 
						|
//   - Lowercases the previous value.
 | 
						|
//     Example: {{ .DisplayName | lowercase }}
 | 
						|
//
 | 
						|
// - replace
 | 
						|
//   - Performs a string find & replace
 | 
						|
//     Example: {{ .DisplayName | replace - _ }}
 | 
						|
//
 | 
						|
// - sha256
 | 
						|
//   - SHA256 hashes the previous value.
 | 
						|
//     Example: {{ .DisplayName | sha256 }}
 | 
						|
//
 | 
						|
// - base64
 | 
						|
//   - base64 encodes the previous value.
 | 
						|
//     Example: {{ .DisplayName | base64 }}
 | 
						|
//
 | 
						|
// - unix_time
 | 
						|
//   - Provides the current unix time in seconds.
 | 
						|
//     Example: {{ unix_time }}
 | 
						|
//
 | 
						|
// - unix_time_millis
 | 
						|
//   - Provides the current unix time in milliseconds.
 | 
						|
//     Example: {{ unix_time_millis }}
 | 
						|
//
 | 
						|
// - timestamp
 | 
						|
//   - Provides the current time. Must include a standard Go format string
 | 
						|
//
 | 
						|
// - uuid
 | 
						|
//   - Generates a UUID
 | 
						|
//     Example: {{ uuid }}
 | 
						|
type StringTemplate struct {
 | 
						|
	rawTemplate string
 | 
						|
	tmpl        *template.Template
 | 
						|
	funcMap     template.FuncMap
 | 
						|
}
 | 
						|
 | 
						|
// NewTemplate creates a StringTemplate. No arguments are required
 | 
						|
// as this has reasonable defaults for all values.
 | 
						|
// The default template is specified in the DefaultTemplate constant.
 | 
						|
func NewTemplate(opts ...Opt) (up StringTemplate, err error) {
 | 
						|
	up = StringTemplate{
 | 
						|
		funcMap: map[string]interface{}{
 | 
						|
			"random":          base62.Random,
 | 
						|
			"truncate":        truncate,
 | 
						|
			"truncate_sha256": truncateSHA256,
 | 
						|
			"uppercase":       uppercase,
 | 
						|
			"lowercase":       lowercase,
 | 
						|
			"replace":         replace,
 | 
						|
			"sha256":          hashSHA256,
 | 
						|
			"base64":          encodeBase64,
 | 
						|
 | 
						|
			"unix_time":        unixTime,
 | 
						|
			"unix_time_millis": unixTimeMillis,
 | 
						|
			"timestamp":        timestamp,
 | 
						|
			"uuid":             uuid,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	merr := &multierror.Error{}
 | 
						|
	for _, opt := range opts {
 | 
						|
		merr = multierror.Append(merr, opt(&up))
 | 
						|
	}
 | 
						|
 | 
						|
	err = merr.ErrorOrNil()
 | 
						|
	if err != nil {
 | 
						|
		return up, err
 | 
						|
	}
 | 
						|
 | 
						|
	if up.rawTemplate == "" {
 | 
						|
		return StringTemplate{}, fmt.Errorf("missing template")
 | 
						|
	}
 | 
						|
 | 
						|
	tmpl, err := template.New("template").
 | 
						|
		Funcs(up.funcMap).
 | 
						|
		Parse(up.rawTemplate)
 | 
						|
	if err != nil {
 | 
						|
		return StringTemplate{}, fmt.Errorf("unable to parse template: %w", err)
 | 
						|
	}
 | 
						|
	up.tmpl = tmpl
 | 
						|
 | 
						|
	return up, nil
 | 
						|
}
 | 
						|
 | 
						|
// Generate based on the provided template
 | 
						|
func (up StringTemplate) Generate(data interface{}) (string, error) {
 | 
						|
	if up.tmpl == nil || up.rawTemplate == "" {
 | 
						|
		return "", fmt.Errorf("failed to generate: template not initialized")
 | 
						|
	}
 | 
						|
	str := &strings.Builder{}
 | 
						|
	err := up.tmpl.Execute(str, data)
 | 
						|
	if err != nil {
 | 
						|
		return "", fmt.Errorf("unable to apply template: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return str.String(), nil
 | 
						|
}
 |