github.com/hashicorp/vault/sdk@v0.13.0/database/helper/credsutil/usernames.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package credsutil
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  	"time"
    10  )
    11  
    12  //go:generate enumer -type=CaseOp -transform=snake
    13  type CaseOp int
    14  
    15  const (
    16  	KeepCase CaseOp = iota
    17  	Uppercase
    18  	Lowercase
    19  )
    20  
    21  type usernameBuilder struct {
    22  	displayName string
    23  	roleName    string
    24  	separator   string
    25  
    26  	maxLen        int
    27  	caseOperation CaseOp
    28  }
    29  
    30  func (ub usernameBuilder) makeUsername() (string, error) {
    31  	userUUID, err := RandomAlphaNumeric(20, false)
    32  	if err != nil {
    33  		return "", err
    34  	}
    35  
    36  	now := fmt.Sprint(time.Now().Unix())
    37  
    38  	username := joinNonEmpty(ub.separator,
    39  		"v",
    40  		ub.displayName,
    41  		ub.roleName,
    42  		userUUID,
    43  		now)
    44  	username = trunc(username, ub.maxLen)
    45  	switch ub.caseOperation {
    46  	case Lowercase:
    47  		username = strings.ToLower(username)
    48  	case Uppercase:
    49  		username = strings.ToUpper(username)
    50  	}
    51  
    52  	return username, nil
    53  }
    54  
    55  type UsernameOpt func(*usernameBuilder)
    56  
    57  func DisplayName(dispName string, maxLength int) UsernameOpt {
    58  	return func(b *usernameBuilder) {
    59  		b.displayName = trunc(dispName, maxLength)
    60  	}
    61  }
    62  
    63  func RoleName(roleName string, maxLength int) UsernameOpt {
    64  	return func(b *usernameBuilder) {
    65  		b.roleName = trunc(roleName, maxLength)
    66  	}
    67  }
    68  
    69  func Separator(sep string) UsernameOpt {
    70  	return func(b *usernameBuilder) {
    71  		b.separator = sep
    72  	}
    73  }
    74  
    75  func MaxLength(maxLen int) UsernameOpt {
    76  	return func(b *usernameBuilder) {
    77  		b.maxLen = maxLen
    78  	}
    79  }
    80  
    81  func Case(c CaseOp) UsernameOpt {
    82  	return func(b *usernameBuilder) {
    83  		b.caseOperation = c
    84  	}
    85  }
    86  
    87  func ToLower() UsernameOpt {
    88  	return Case(Lowercase)
    89  }
    90  
    91  func ToUpper() UsernameOpt {
    92  	return Case(Uppercase)
    93  }
    94  
    95  func GenerateUsername(opts ...UsernameOpt) (string, error) {
    96  	b := usernameBuilder{
    97  		separator:     "_",
    98  		maxLen:        100,
    99  		caseOperation: KeepCase,
   100  	}
   101  
   102  	for _, opt := range opts {
   103  		opt(&b)
   104  	}
   105  
   106  	return b.makeUsername()
   107  }
   108  
   109  func trunc(str string, l int) string {
   110  	switch {
   111  	case l > 0:
   112  		if l > len(str) {
   113  			return str
   114  		}
   115  		return str[:l]
   116  	case l == 0:
   117  		return str
   118  	default:
   119  		return ""
   120  	}
   121  }
   122  
   123  func joinNonEmpty(sep string, vals ...string) string {
   124  	if sep == "" {
   125  		return strings.Join(vals, sep)
   126  	}
   127  	switch len(vals) {
   128  	case 0:
   129  		return ""
   130  	case 1:
   131  		return vals[0]
   132  	}
   133  	builder := &strings.Builder{}
   134  	for _, val := range vals {
   135  		if val == "" {
   136  			continue
   137  		}
   138  		if builder.Len() > 0 {
   139  			builder.WriteString(sep)
   140  		}
   141  		builder.WriteString(val)
   142  	}
   143  	return builder.String()
   144  }