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