mirror of https://github.com/coder/coder.git
feat: Add cryptorand package for random string and number generation (#32)
* feat: Add cryptorand package for random string and number generation This package is taken from the monorepo, and was renamed from crand for improved clarity. It will be used for API key generation. * Remove "Must" functions There is little precedence of functions leading with Must being idiomatic in Go code. Ignoring errors in favor of a panic is dangerous in highly-reliable code. * Remove unused must.go
This commit is contained in:
parent
4dc6e35c24
commit
6e6eee633c
|
@ -0,0 +1,194 @@
|
|||
package cryptorand
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// Most of this code is inspired by math/rand, so shares similar
|
||||
// functions and implementations, but uses crypto/rand to generate
|
||||
// random Int63 data.
|
||||
|
||||
// Int64 returns a non-negative random 63-bit integer as a int64.
|
||||
func Int63() (int64, error) {
|
||||
var i int64
|
||||
err := binary.Read(rand.Reader, binary.BigEndian, &i)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("read binary: %w", err)
|
||||
}
|
||||
|
||||
if i < 0 {
|
||||
return -i, nil
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// Uint64 returns a random 64-bit integer as a uint64.
|
||||
func Uint64() (uint64, error) {
|
||||
upper, err := Int63()
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("read upper: %w", err)
|
||||
}
|
||||
|
||||
lower, err := Int63()
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("read lower: %w", err)
|
||||
}
|
||||
|
||||
return uint64(lower)>>31 | uint64(upper)<<32, nil
|
||||
}
|
||||
|
||||
// Int31 returns a non-negative random 31-bit integer as a int32.
|
||||
func Int31() (int32, error) {
|
||||
i, err := Int63()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int32(i >> 32), nil
|
||||
}
|
||||
|
||||
// Uint32 returns a 32-bit value as a uint32.
|
||||
func Uint32() (uint32, error) {
|
||||
i, err := Int63()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return uint32(i >> 31), nil
|
||||
}
|
||||
|
||||
// Int returns a non-negative random integer as a int.
|
||||
func Int() (int, error) {
|
||||
i, err := Int63()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if i < 0 {
|
||||
return int(-i), nil
|
||||
}
|
||||
return int(i), nil
|
||||
}
|
||||
|
||||
// Int63n returns a non-negative random integer in [0,n) as a int64.
|
||||
func Int63n(n int64) (int64, error) {
|
||||
if n <= 0 {
|
||||
panic("invalid argument to Int63n")
|
||||
}
|
||||
|
||||
max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
|
||||
i, err := Int63()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
for i > max {
|
||||
i, err = Int63()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return i % n, nil
|
||||
}
|
||||
|
||||
// Int31n returns a non-negative integer in [0,n) as a int32.
|
||||
func Int31n(n int32) (int32, error) {
|
||||
i, err := Uint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return UnbiasedModulo32(i, n)
|
||||
}
|
||||
|
||||
// UnbiasedModulo32 uniformly modulos v by n over a sufficiently large data
|
||||
// set, regenerating v if necessary. n must be > 0. All input bits in v must be
|
||||
// fully random, you cannot cast a random uint8/uint16 for input into this
|
||||
// function.
|
||||
func UnbiasedModulo32(v uint32, n int32) (int32, error) {
|
||||
prod := uint64(v) * uint64(n)
|
||||
low := uint32(prod)
|
||||
if low < uint32(n) {
|
||||
thresh := uint32(-n) % uint32(n)
|
||||
for low < thresh {
|
||||
var err error
|
||||
v, err = Uint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
prod = uint64(v) * uint64(n)
|
||||
low = uint32(prod)
|
||||
}
|
||||
}
|
||||
return int32(prod >> 32), nil
|
||||
}
|
||||
|
||||
// Intn returns a non-negative integer in [0,n) as a int.
|
||||
func Intn(n int) (int, error) {
|
||||
if n <= 0 {
|
||||
panic("n must be a positive nonzero number")
|
||||
}
|
||||
|
||||
if n <= 1<<31-1 {
|
||||
i, err := Int31n(int32(n))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(i), nil
|
||||
}
|
||||
|
||||
i, err := Int63n(int64(n))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(i), nil
|
||||
}
|
||||
|
||||
// Float64 returns a random number in [0.0,1.0) as a float64.
|
||||
func Float64() (float64, error) {
|
||||
again:
|
||||
i, err := Int63n(1 << 53)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
f := (float64(i) / (1 << 53))
|
||||
if f == 1 {
|
||||
goto again
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Float32 returns a random number in [0.0,1.0) as a float32.
|
||||
func Float32() (float32, error) {
|
||||
again:
|
||||
i, err := Float64()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
f := float32(i)
|
||||
if f == 1 {
|
||||
goto again
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Bool returns a random true/false value as a bool.
|
||||
func Bool() (bool, error) {
|
||||
i, err := Uint64()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// True if the least significant bit is 1
|
||||
return i&1 == 1, nil
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
package cryptorand_test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
"github.com/coder/coder/cryptorand"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInt63(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
v, err := cryptorand.Int63()
|
||||
require.NoError(t, err, "unexpected error from Int63")
|
||||
t.Logf("value: %v <- random?", v)
|
||||
require.True(t, v >= 0, "values must be positive")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
v, err := cryptorand.Uint64()
|
||||
require.NoError(t, err, "unexpected error from Uint64")
|
||||
t.Logf("value: %v <- random?", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt31(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
v, err := cryptorand.Int31()
|
||||
require.NoError(t, err, "unexpected error from Int31")
|
||||
t.Logf("value: %v <- random?", v)
|
||||
require.True(t, v >= 0, "values must be positive")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnbiasedModulo32(t *testing.T) {
|
||||
t.Parallel()
|
||||
const mod = 7
|
||||
dist := [mod]uint32{}
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
b := [4]byte{}
|
||||
_, _ = rand.Read(b[:])
|
||||
v, err := cryptorand.UnbiasedModulo32(binary.BigEndian.Uint32(b[:]), mod)
|
||||
require.NoError(t, err, "unexpected error from UnbiasedModulo32")
|
||||
dist[v]++
|
||||
}
|
||||
|
||||
t.Logf("dist: %+v <- evenly distributed?", dist)
|
||||
}
|
||||
|
||||
func TestUint32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
v, err := cryptorand.Uint32()
|
||||
require.NoError(t, err, "unexpected error from Uint32")
|
||||
t.Logf("value: %v <- random?", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
v, err := cryptorand.Int()
|
||||
require.NoError(t, err, "unexpected error from Int")
|
||||
t.Logf("value: %v <- random?", v)
|
||||
require.True(t, v >= 0, "values must be positive")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt63n(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
v, err := cryptorand.Int63n(1 << 35)
|
||||
require.NoError(t, err, "unexpected error from Int63n")
|
||||
t.Logf("value: %v <- random?", v)
|
||||
require.True(t, v >= 0, "values must be positive")
|
||||
require.True(t, v < 1<<35, "values must be less than 1<<35")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt31n(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
v, err := cryptorand.Int31n(100)
|
||||
require.NoError(t, err, "unexpected error from Int31n")
|
||||
t.Logf("value: %v <- random?", v)
|
||||
require.True(t, v >= 0, "values must be positive")
|
||||
require.True(t, v < 100, "values must be less than 100")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntn(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
v, err := cryptorand.Intn(100)
|
||||
require.NoError(t, err, "unexpected error from Intn")
|
||||
t.Logf("value: %v <- random?", v)
|
||||
require.True(t, v >= 0, "values must be positive")
|
||||
require.True(t, v < 100, "values must be less than 100")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
v, err := cryptorand.Float64()
|
||||
require.NoError(t, err, "unexpected error from Float64")
|
||||
t.Logf("value: %v <- random?", v)
|
||||
require.True(t, v >= 0.0, "values must be positive")
|
||||
require.True(t, v < 1.0, "values must be less than 1.0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
v, err := cryptorand.Float32()
|
||||
require.NoError(t, err, "unexpected error from Float32")
|
||||
t.Logf("value: %v <- random?", v)
|
||||
require.True(t, v >= 0.0, "values must be positive")
|
||||
require.True(t, v < 1.0, "values must be less than 1.0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBool(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const iterations = 10000
|
||||
trueCount := 0
|
||||
|
||||
for i := 0; i < iterations; i += 1 {
|
||||
v, err := cryptorand.Bool()
|
||||
require.NoError(t, err, "unexpected error from Bool")
|
||||
if v {
|
||||
trueCount++
|
||||
}
|
||||
}
|
||||
|
||||
percentage := (float64(trueCount) / iterations) * 100
|
||||
t.Logf("number of true values: %d of %d total (%.2f%%)", trueCount, iterations, percentage)
|
||||
require.True(t, percentage > 48, "expected more than 48 percent of values to be true")
|
||||
require.True(t, percentage < 52, "expected less than 52 percent of values to be true")
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package cryptorand
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Charsets
|
||||
const (
|
||||
// Numeric includes decimal numbers (0-9)
|
||||
Numeric = "0123456789"
|
||||
|
||||
// Upper is uppercase characters in the Latin alphabet
|
||||
Upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
// Lower is lowercase characters in the Latin alphabet
|
||||
Lower = "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
// Alpha is upper or lowercase alphabetic characters
|
||||
Alpha = Upper + Lower
|
||||
|
||||
// Default is uppercase, lowercase, or numeric characters
|
||||
Default = Numeric + Alpha
|
||||
|
||||
// Hex is hexadecimal lowercase characters
|
||||
Hex = "0123456789abcdef"
|
||||
|
||||
// Human creates strings which are easily distinguishable from
|
||||
// others created with the same charset. It contains most lowercase
|
||||
// alphanumeric characters without 0,o,i,1,l.
|
||||
Human = "23456789abcdefghjkmnpqrstuvwxyz"
|
||||
)
|
||||
|
||||
// StringCharset generates a random string using the provided charset and size
|
||||
func StringCharset(charSetStr string, size int) (string, error) {
|
||||
charSet := []rune(charSetStr)
|
||||
|
||||
if len(charSet) == 0 || size == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// This buffer facilitates pre-emptively creation of random uint32s
|
||||
// to reduce syscall overhead.
|
||||
ibuf := make([]byte, 4*size)
|
||||
|
||||
_, err := rand.Read(ibuf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
buf.Grow(size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
c, err := UnbiasedModulo32(
|
||||
binary.BigEndian.Uint32(ibuf[i*4:(i+1)*4]),
|
||||
int32(len(charSet)),
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, _ = buf.WriteRune(charSet[c])
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// String returns a random string using Default.
|
||||
func String(size int) (string, error) {
|
||||
return StringCharset(Default, size)
|
||||
}
|
||||
|
||||
// HexString returns a hexadecimal string of given length.
|
||||
func HexString(size int) (string, error) {
|
||||
return StringCharset(Hex, size)
|
||||
}
|
||||
|
||||
// Sha1String returns a 40-character hexadecimal string, which matches
|
||||
// the length of a SHA-1 hash (160 bits).
|
||||
func Sha1String() (string, error) {
|
||||
return StringCharset(Hex, 40)
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
package cryptorand_test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/coder/coder/cryptorand"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
rs, err := cryptorand.String(10)
|
||||
require.NoError(t, err, "unexpected error from String")
|
||||
t.Logf("value: %v <- random?", rs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringCharset(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
Name string
|
||||
Charset string
|
||||
HelperFunc func(int) (string, error)
|
||||
Length int
|
||||
}{
|
||||
{
|
||||
Name: "MultiByte-20",
|
||||
Charset: "💓😘💓🌷",
|
||||
Length: 20,
|
||||
},
|
||||
{
|
||||
Name: "MultiByte-7",
|
||||
Charset: "😇🥰😍🤩😘😗☺️😚😙🥲😋😛😜🤪😝🤑",
|
||||
Length: 7,
|
||||
},
|
||||
{
|
||||
Name: "MixedBytes",
|
||||
Charset: "🍋🍌🍍🥭🍎🍏🍐🍑🍒🍓🫐🥝🍅🫒🥥🥑🍆🥔abcdefg1234",
|
||||
Length: 10,
|
||||
},
|
||||
{
|
||||
Name: "Empty",
|
||||
Charset: cryptorand.Default,
|
||||
Length: 0,
|
||||
HelperFunc: cryptorand.String,
|
||||
},
|
||||
{
|
||||
Name: "Numeric",
|
||||
Charset: cryptorand.Numeric,
|
||||
Length: 1,
|
||||
},
|
||||
{
|
||||
Name: "Upper",
|
||||
Charset: cryptorand.Upper,
|
||||
Length: 3,
|
||||
},
|
||||
{
|
||||
Name: "Lower",
|
||||
Charset: cryptorand.Lower,
|
||||
Length: 10,
|
||||
},
|
||||
{
|
||||
Name: "Alpha",
|
||||
Charset: cryptorand.Alpha,
|
||||
Length: 20,
|
||||
},
|
||||
{
|
||||
Name: "Default",
|
||||
Charset: cryptorand.Default,
|
||||
Length: 10,
|
||||
},
|
||||
{
|
||||
Name: "Hex",
|
||||
Charset: cryptorand.Hex,
|
||||
Length: 15,
|
||||
HelperFunc: cryptorand.HexString,
|
||||
},
|
||||
{
|
||||
Name: "Human",
|
||||
Charset: cryptorand.Human,
|
||||
Length: 20,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
rs, err := cryptorand.StringCharset(test.Charset, test.Length)
|
||||
require.NoError(t, err, "unexpected error from StringCharset")
|
||||
require.Equal(t, test.Length, utf8.RuneCountInString(rs), "expected RuneCountInString to match requested")
|
||||
if i == 0 {
|
||||
t.Logf("value: %v <- random?", rs)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if test.HelperFunc != nil {
|
||||
t.Run(test.Name+"HelperFunc", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
rs, err := test.HelperFunc(test.Length)
|
||||
require.NoError(t, err, "unexpected error from HelperFunc")
|
||||
require.Equal(t, test.Length, utf8.RuneCountInString(rs), "expected RuneCountInString to match requested")
|
||||
if i == 0 {
|
||||
t.Logf("value: %v <- random?", rs)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSha1String(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
rs, err := cryptorand.Sha1String()
|
||||
require.NoError(t, err, "unexpected error from String")
|
||||
require.Equal(t, 40, utf8.RuneCountInString(rs), "expected RuneCountInString to match requested")
|
||||
t.Logf("value: %v <- random?", rs)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkString20(b *testing.B) {
|
||||
b.SetBytes(20)
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = cryptorand.String(20)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkStringUnsafe20(b *testing.B) {
|
||||
mkstring := func(charSetStr string, size int) (string, error) {
|
||||
charSet := []rune(charSetStr)
|
||||
|
||||
// This buffer facilitates pre-emptively creation of random uint32s
|
||||
// to reduce syscall overhead.
|
||||
ibuf := make([]byte, 4*size)
|
||||
|
||||
_, err := rand.Read(ibuf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
buf.Grow(size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
n := binary.BigEndian.Uint32(ibuf[i*4 : (i+1)*4])
|
||||
_, _ = buf.WriteRune(charSet[n%uint32(len(charSet))])
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
b.SetBytes(20)
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = mkstring(cryptorand.Default, 20)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkStringBigint20(b *testing.B) {
|
||||
mkstring := func(charSetStr string, size int) (string, error) {
|
||||
charSet := []rune(charSetStr)
|
||||
|
||||
var buf strings.Builder
|
||||
buf.Grow(size)
|
||||
|
||||
bi := big.NewInt(int64(size))
|
||||
for i := 0; i < size; i++ {
|
||||
num, err := rand.Int(rand.Reader, bi)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, _ = buf.WriteRune(charSet[num.Uint64()%uint64(len(charSet))])
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
b.SetBytes(20)
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = mkstring(cryptorand.Default, 20)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkStringRuneCast(b *testing.B) {
|
||||
s := strings.Repeat("0", 20)
|
||||
b.SetBytes(int64(len(s)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = []rune(s)
|
||||
}
|
||||
}
|
4
go.mod
4
go.mod
|
@ -18,6 +18,7 @@ require (
|
|||
github.com/hashicorp/hc-install v0.3.1
|
||||
github.com/hashicorp/terraform-config-inspect v0.0.0-20211115214459-90acf1ca460f
|
||||
github.com/hashicorp/terraform-exec v0.15.0
|
||||
github.com/justinas/nosurf v1.1.1
|
||||
github.com/lib/pq v1.10.4
|
||||
github.com/ory/dockertest/v3 v3.8.1
|
||||
github.com/pion/datachannel v1.5.2
|
||||
|
@ -26,6 +27,7 @@ require (
|
|||
github.com/pion/webrtc/v3 v3.1.13
|
||||
github.com/spf13/cobra v1.3.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/unrolled/secure v1.0.9
|
||||
go.uber.org/atomic v1.7.0
|
||||
go.uber.org/goleak v1.1.12
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
||||
|
@ -65,7 +67,6 @@ require (
|
|||
github.com/hashicorp/terraform-json v0.13.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/justinas/nosurf v1.1.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
|
||||
|
@ -91,7 +92,6 @@ require (
|
|||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/unrolled/secure v1.0.9 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
|
|
1
go.sum
1
go.sum
|
@ -1159,6 +1159,7 @@ github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/
|
|||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
|
||||
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
||||
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
|
|
Loading…
Reference in New Issue