github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/legacy/helper/acctest/random.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package acctest
     5  
     6  import (
     7  	"bytes"
     8  	crand "crypto/rand"
     9  	"crypto/rsa"
    10  	"crypto/x509"
    11  	"crypto/x509/pkix"
    12  	"encoding/pem"
    13  	"fmt"
    14  	"math/big"
    15  	"math/rand"
    16  	"net"
    17  	"strings"
    18  	"time"
    19  
    20  	"golang.org/x/crypto/ssh"
    21  
    22  	"github.com/apparentlymart/go-cidr/cidr"
    23  )
    24  
    25  func init() {
    26  	rand.Seed(time.Now().UTC().UnixNano())
    27  }
    28  
    29  // Helpers for generating random tidbits for use in identifiers to prevent
    30  // collisions in acceptance tests.
    31  
    32  // RandInt generates a random integer
    33  func RandInt() int {
    34  	return rand.New(rand.NewSource(time.Now().UnixNano())).Int()
    35  }
    36  
    37  // RandomWithPrefix is used to generate a unique name with a prefix, for
    38  // randomizing names in acceptance tests
    39  func RandomWithPrefix(name string) string {
    40  	return fmt.Sprintf("%s-%d", name, rand.New(rand.NewSource(time.Now().UnixNano())).Int())
    41  }
    42  
    43  func RandIntRange(min int, max int) int {
    44  	source := rand.New(rand.NewSource(time.Now().UnixNano()))
    45  	rangeMax := max - min
    46  
    47  	return int(source.Int31n(int32(rangeMax)))
    48  }
    49  
    50  // RandString generates a random alphanumeric string of the length specified
    51  func RandString(strlen int) string {
    52  	return RandStringFromCharSet(strlen, CharSetAlphaNum)
    53  }
    54  
    55  // RandStringFromCharSet generates a random string by selecting characters from
    56  // the charset provided
    57  func RandStringFromCharSet(strlen int, charSet string) string {
    58  	result := make([]byte, strlen)
    59  	for i := 0; i < strlen; i++ {
    60  		result[i] = charSet[rand.Intn(len(charSet))]
    61  	}
    62  	return string(result)
    63  }
    64  
    65  // RandSSHKeyPair generates a public and private SSH key pair. The public key is
    66  // returned in OpenSSH format, and the private key is PEM encoded.
    67  func RandSSHKeyPair(comment string) (string, string, error) {
    68  	privateKey, privateKeyPEM, err := genPrivateKey()
    69  	if err != nil {
    70  		return "", "", err
    71  	}
    72  
    73  	publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey)
    74  	if err != nil {
    75  		return "", "", err
    76  	}
    77  	keyMaterial := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(publicKey)))
    78  	return fmt.Sprintf("%s %s", keyMaterial, comment), privateKeyPEM, nil
    79  }
    80  
    81  // RandTLSCert generates a self-signed TLS certificate with a newly created
    82  // private key, and returns both the cert and the private key PEM encoded.
    83  func RandTLSCert(orgName string) (string, string, error) {
    84  	template := &x509.Certificate{
    85  		SerialNumber: big.NewInt(int64(RandInt())),
    86  		Subject: pkix.Name{
    87  			Organization: []string{orgName},
    88  		},
    89  		NotBefore:             time.Now(),
    90  		NotAfter:              time.Now().Add(24 * time.Hour),
    91  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
    92  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    93  		BasicConstraintsValid: true,
    94  	}
    95  
    96  	privateKey, privateKeyPEM, err := genPrivateKey()
    97  	if err != nil {
    98  		return "", "", err
    99  	}
   100  
   101  	cert, err := x509.CreateCertificate(crand.Reader, template, template, &privateKey.PublicKey, privateKey)
   102  	if err != nil {
   103  		return "", "", err
   104  	}
   105  
   106  	certPEM, err := pemEncode(cert, "CERTIFICATE")
   107  	if err != nil {
   108  		return "", "", err
   109  	}
   110  
   111  	return certPEM, privateKeyPEM, nil
   112  }
   113  
   114  // RandIpAddress returns a random IP address in the specified CIDR block.
   115  // The prefix length must be less than 31.
   116  func RandIpAddress(s string) (string, error) {
   117  	_, network, err := net.ParseCIDR(s)
   118  	if err != nil {
   119  		return "", err
   120  	}
   121  
   122  	firstIp, lastIp := cidr.AddressRange(network)
   123  	first := &big.Int{}
   124  	first.SetBytes([]byte(firstIp))
   125  	last := &big.Int{}
   126  	last.SetBytes([]byte(lastIp))
   127  	r := &big.Int{}
   128  	r.Sub(last, first)
   129  	if len := r.BitLen(); len > 31 {
   130  		return "", fmt.Errorf("CIDR range is too large: %d", len)
   131  	}
   132  
   133  	max := int(r.Int64())
   134  	if max == 0 {
   135  		// panic: invalid argument to Int31n
   136  		return firstIp.String(), nil
   137  	}
   138  
   139  	host, err := cidr.Host(network, RandIntRange(0, max))
   140  	if err != nil {
   141  		return "", err
   142  	}
   143  
   144  	return host.String(), nil
   145  }
   146  
   147  func genPrivateKey() (*rsa.PrivateKey, string, error) {
   148  	privateKey, err := rsa.GenerateKey(crand.Reader, 1024)
   149  	if err != nil {
   150  		return nil, "", err
   151  	}
   152  
   153  	privateKeyPEM, err := pemEncode(x509.MarshalPKCS1PrivateKey(privateKey), "RSA PRIVATE KEY")
   154  	if err != nil {
   155  		return nil, "", err
   156  	}
   157  
   158  	return privateKey, privateKeyPEM, nil
   159  }
   160  
   161  func pemEncode(b []byte, block string) (string, error) {
   162  	var buf bytes.Buffer
   163  	pb := &pem.Block{Type: block, Bytes: b}
   164  	if err := pem.Encode(&buf, pb); err != nil {
   165  		return "", err
   166  	}
   167  
   168  	return buf.String(), nil
   169  }
   170  
   171  const (
   172  	// CharSetAlphaNum is the alphanumeric character set for use with
   173  	// RandStringFromCharSet
   174  	CharSetAlphaNum = "abcdefghijklmnopqrstuvwxyz012346789"
   175  
   176  	// CharSetAlpha is the alphabetical character set for use with
   177  	// RandStringFromCharSet
   178  	CharSetAlpha = "abcdefghijklmnopqrstuvwxyz"
   179  )