-
Notifications
You must be signed in to change notification settings - Fork 62
/
string.go
65 lines (57 loc) · 1.9 KB
/
string.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
// SPDX-License-Identifier: AGPL-3.0-only
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
package random
import (
"bufio"
"crypto/rand"
"io"
"github.com/bangumi/server/internal/pkg/generic/pool"
)
var p = pool.New(func() *bufio.Reader {
return bufio.NewReader(rand.Reader)
})
// we may never need to change these values.
const base62Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const base62CharsLength = 62 // len(base62Chars)
const base62MaxByte byte = 255 - (256 % base62CharsLength) //nolint:gomnd
// Base62String generate a cryptographically secure base62 string in given length.
// Will panic if it can't read from 'crypto/rand'.
func Base62String(length int) string {
reader := p.Get()
defer p.Put(reader)
b := make([]byte, length)
// storage for random bytes.
r := make([]byte, length+(length/4)) //nolint:gomnd
i := 0
for {
n, err := io.ReadFull(reader, r)
if err != nil {
panic("unexpected error happened when reading from bufio.NewReader(crypto/rand.Reader)")
}
if n != len(r) {
panic("partial reads occurred when reading from bufio.NewReader(crypto/rand.Reader)")
}
for _, rb := range r {
if rb > base62MaxByte {
// Skip this number to avoid modulo bias.
continue
}
b[i] = base62Chars[rb%base62CharsLength]
i++
if i == length {
return string(b)
}
}
}
}