-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbuiltins.go
181 lines (163 loc) · 4.54 KB
/
builtins.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
177
178
179
180
181
package prefixgen
import (
"encoding/hex"
"fmt"
"math/rand"
"strconv"
"time"
)
const defaultRandomStringSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
// builtin represents a built-in function for use in prefix generators. A builtin parses and closes
// over a slice of string arguments. Non-deterministic builtins will be re-evaluated each time,
// producing new results.
type builtin func([]string) (func() []byte, error)
// Builtins is a collection of built-in functions which can be referenced in the generator provided
// to New.
var Builtins = map[string]builtin{
"hex": Hex,
"random_string": RandomString,
"random_int": RandomInt,
"random_bytes": RandomBytes,
}
var mathrand = rand.New(rand.NewSource(time.Now().UnixNano()))
// Hex is a builtin function (see New and Builtins).
//
// Args:
//
// 0 (hex input): string
// even in length, containing only characters in [0-9A-Fa-f]
//
// Parses argument 0 into raw bytes and prints to the output.
//
// Example:
//
// $hex(BEEFFACE33)
func Hex(args []string) (func() []byte, error) {
if len(args) != 1 {
return nil, fmt.Errorf("expected 1 arg, received %d", len(args))
}
b, err := hex.DecodeString(args[0])
if err != nil {
return nil, err
}
return func() []byte { return b }, nil
}
// RandomString is a builtin function (see New and Builtins).
//
// Args:
//
// 0 (min length): integer
// 1 (max length): integer
// 2 (character set): string, optional
//
// Produces a string, whose length will be [min length, max length). If a character set is provided,
// only the specified characters will be considered. The default character set is the set of 26
// alphabetic characters, lower and upper case.
//
// Examples:
//
// $random_string(1, 10)
// $random_string(1, 10, aeiou)
func RandomString(args []string) (func() []byte, error) {
if len(args) < 2 {
return nil, fmt.Errorf("expected at least 2 args, received %d", len(args))
}
minLen, err := strconv.Atoi(args[0])
if err != nil {
return nil, fmt.Errorf("failed to parse min len: %w", err)
}
maxLen, err := strconv.Atoi(args[1])
if err != nil {
return nil, fmt.Errorf("failed to parse max len: %w", err)
}
chars := []rune(defaultRandomStringSet)
if len(args) > 2 {
chars = []rune(args[2])
}
return func() []byte {
runes := make([]rune, mathrand.Intn(maxLen-minLen)+minLen)
for i := range runes {
runes[i] = chars[mathrand.Intn(len(chars))]
}
return []byte(string(runes))
}, nil
}
// RandomInt is a builtin function (see New and Builtins).
//
// Args:
//
// 0 (min): integer
// 1 (max): integer
//
// Produces an integer in the range [min, max).
//
// Examples:
//
// $random_int(0, 10)
// $random_int(-1000, 1000)
func RandomInt(args []string) (func() []byte, error) {
if len(args) != 2 {
return nil, fmt.Errorf("expected 2 args, received %d", len(args))
}
minLen, err := strconv.Atoi(args[0])
if err != nil {
return nil, fmt.Errorf("failed to parse min len: %w", err)
}
maxLen, err := strconv.Atoi(args[1])
if err != nil {
return nil, fmt.Errorf("failed to parse max len: %w", err)
}
return func() []byte {
n := mathrand.Intn(maxLen-minLen) + minLen
return []byte(strconv.Itoa(n))
}, nil
}
// RandomBytes is a builtin function (see New and Builtins).
//
// Args:
//
// 0 (min length): integer
// 1 (max length): integer
// 2 (byte set): string, optional
// even in length, containing only characters in [0-9A-Fa-f]
// each group of two characters represents a possible choice
//
// Produces a byte string, whose length will be [min length, max length). If a byte set is provided,
// only the specified bytes will be considered. The default byte set is all possible bytes.
//
// Examples:
//
// $random_bytes(1, 10)
// $random_bytes(1, 10, 010203A1A2A3)
func RandomBytes(args []string) (func() []byte, error) {
if len(args) < 2 {
return nil, fmt.Errorf("expected at least 2 args, received %d", len(args))
}
minLen, err := strconv.Atoi(args[0])
if err != nil {
return nil, fmt.Errorf("failed to parse min len: %w", err)
}
maxLen, err := strconv.Atoi(args[1])
if err != nil {
return nil, fmt.Errorf("failed to parse max len: %w", err)
}
var possibilities []byte
if len(args) > 2 {
possibilities, err = hex.DecodeString(args[2])
if err != nil {
return nil, fmt.Errorf("failed to decode byte set")
}
} else {
possibilities = make([]byte, 256)
for i := 0; i < 256; i++ {
possibilities[i] = byte(i)
}
}
return func() []byte {
b := make([]byte, mathrand.Intn(maxLen-minLen)+minLen)
for i := range b {
b[i] = possibilities[mathrand.Intn(len(possibilities))]
}
return b
}, nil
}