github.com/greenpau/go-authcrunch@v1.1.4/pkg/util/random.go (about) 1 // Copyright 2022 Paul Greenberg greenpau@outlook.com 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package util 16 17 import ( 18 "crypto/rand" 19 "encoding/base32" 20 "io" 21 // "math" 22 "math/big" 23 mathrand "math/rand" 24 "unicode" 25 ) 26 27 const charset = "abcdefghijklmnopqrstuvwxyz" + 28 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 29 30 var charsetTable = &unicode.RangeTable{ 31 R16: []unicode.Range16{ 32 {0x0061, 0x007a, 1}, // a-z, where a is hex 61 33 {0x0041, 0x005a, 1}, // A-Z, where A is hex 41 34 {0x0030, 0x0039, 1}, // 0-9, where 0 is hex 30 35 }, 36 LatinOffset: 1, 37 } 38 39 func genRandInt(i int) uint32 { 40 n, err := rand.Int(rand.Reader, big.NewInt(int64(i))) 41 if err != nil { 42 return uint32(mathrand.Intn(i)) 43 } 44 //if n.Uint64() > math.MaxUint32+1 { 45 // return uint32(n.Uint64() & uint32(0xFFFFFFFF)) 46 //} 47 return uint32(n.Uint64()) 48 } 49 50 func gen(length uint32, charset string) string { 51 charsetLen := byte(len(charset)) 52 b := make([]byte, length) 53 if _, err := io.ReadFull(rand.Reader, b); err != nil { 54 // for i uint32 := 0; i < length; i++ { 55 for i := uint32(0); i < length; { 56 b[i] = charset[mathrand.Intn(len(charset))] 57 } 58 return string(b) 59 } 60 61 for i, char := range b { 62 b[i] = byte(charset[char%charsetLen]) 63 } 64 65 return string(b) 66 } 67 68 // GetRandomString returns X character long random string. 69 func GetRandomString(i int) string { 70 if i < 1 { 71 i = 40 72 } 73 return gen(uint32(i), charset) 74 } 75 76 // GetRandomStringFromRange generates random string of a random length. The 77 // random lenght is bounded by a and b. 78 func GetRandomStringFromRange(a, b int) string { 79 var i uint32 80 if a > b { 81 i = genRandInt(a-b) + uint32(b) 82 } else { 83 i = genRandInt(b-a) + uint32(a) 84 } 85 return gen(i, charset) 86 } 87 88 // GetRandomEncodedStringFromRange return the number returned by 89 // GetRandomStringFromRange() and encoded with Base32 90 func GetRandomEncodedStringFromRange(a, b int) string { 91 s := GetRandomStringFromRange(a, b) 92 return base32.StdEncoding.EncodeToString([]byte(s)) 93 } 94 95 // GetRandomStringFromRangeWithCharset generates random string of a random length. The 96 // random lenght is bounded by a and b. The charset is provided. 97 func GetRandomStringFromRangeWithCharset(a, b int, cs string) string { 98 var i uint32 99 if a > b { 100 i = genRandInt(a-b) + uint32(b) 101 } else { 102 i = genRandInt(b-a) + uint32(a) 103 } 104 return gen(i, cs) 105 } 106 107 // IsMalformedRandomString checks whether the provided string was generated by 108 // the GetRandomStringFromRange() function. 109 func IsMalformedRandomString(s string, a, b int) bool { 110 switch { 111 case len(s) == 0: 112 return false 113 case (len(s) < a) || (len(s) > b): 114 return true 115 } 116 for _, char := range s { 117 if !unicode.IsLetter(char) && !unicode.IsNumber(char) { 118 return true 119 } 120 if !unicode.In(char, charsetTable) { 121 return false 122 } 123 } 124 return false 125 } 126 127 // SanitizeSessionID sanitizes provided Session ID. 128 func SanitizeSessionID(s string) string { 129 if IsMalformedRandomString(s, 0, 46) { 130 return "MALFORMED" 131 } 132 return s 133 }