[MM-29296] model/user: add lock to source (#16054)
* model/user: add lock to source * guard rand creation with locking * use locked random * remove assignment Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
50e29cb47a
Коммит
b30acfdee6
@@ -14,6 +14,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@@ -890,7 +891,22 @@ func UsersWithGroupsAndCountFromJson(data io.Reader) *UsersWithGroupsAndCount {
|
|||||||
return uwg
|
return uwg
|
||||||
}
|
}
|
||||||
|
|
||||||
var passwordRandomSource = rand.NewSource(time.Now().Unix())
|
type lockedRand struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
rn *rand.Rand
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *lockedRand) Intn(n int) int {
|
||||||
|
r.mu.Lock()
|
||||||
|
m := r.rn.Intn(n)
|
||||||
|
r.mu.Unlock()
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
var passwordRandom = lockedRand{
|
||||||
|
rn: rand.New(rand.NewSource(time.Now().Unix())),
|
||||||
|
}
|
||||||
|
|
||||||
var passwordSpecialChars = "!$%^&*(),."
|
var passwordSpecialChars = "!$%^&*(),."
|
||||||
var passwordNumbers = "0123456789"
|
var passwordNumbers = "0123456789"
|
||||||
var passwordUpperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
var passwordUpperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
@@ -898,16 +914,14 @@ var passwordLowerCaseLetters = "abcdefghijklmnopqrstuvwxyz"
|
|||||||
var passwordAllChars = passwordSpecialChars + passwordNumbers + passwordUpperCaseLetters + passwordLowerCaseLetters
|
var passwordAllChars = passwordSpecialChars + passwordNumbers + passwordUpperCaseLetters + passwordLowerCaseLetters
|
||||||
|
|
||||||
func GeneratePassword(minimumLength int) string {
|
func GeneratePassword(minimumLength int) string {
|
||||||
r := rand.New(passwordRandomSource)
|
|
||||||
|
|
||||||
// Make sure we are guaranteed at least one of each type to meet any possible password complexity requirements.
|
// Make sure we are guaranteed at least one of each type to meet any possible password complexity requirements.
|
||||||
password := string([]rune(passwordUpperCaseLetters)[r.Intn(len(passwordUpperCaseLetters))]) +
|
password := string([]rune(passwordUpperCaseLetters)[passwordRandom.Intn(len(passwordUpperCaseLetters))]) +
|
||||||
string([]rune(passwordNumbers)[r.Intn(len(passwordNumbers))]) +
|
string([]rune(passwordNumbers)[passwordRandom.Intn(len(passwordNumbers))]) +
|
||||||
string([]rune(passwordLowerCaseLetters)[r.Intn(len(passwordLowerCaseLetters))]) +
|
string([]rune(passwordLowerCaseLetters)[passwordRandom.Intn(len(passwordLowerCaseLetters))]) +
|
||||||
string([]rune(passwordSpecialChars)[r.Intn(len(passwordSpecialChars))])
|
string([]rune(passwordSpecialChars)[passwordRandom.Intn(len(passwordSpecialChars))])
|
||||||
|
|
||||||
for len(password) < minimumLength {
|
for len(password) < minimumLength {
|
||||||
i := r.Intn(len(passwordAllChars))
|
i := passwordRandom.Intn(len(passwordAllChars))
|
||||||
password = password + string([]rune(passwordAllChars)[i])
|
password = password + string([]rune(passwordAllChars)[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -353,7 +353,9 @@ func TestUserSlice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGeneratePassword(t *testing.T) {
|
func TestGeneratePassword(t *testing.T) {
|
||||||
passwordRandomSource = rand.NewSource(12345)
|
passwordRandom = lockedRand{
|
||||||
|
rn: rand.New(rand.NewSource(12345)),
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("Should be the minimum length or 4, whichever is less", func(t *testing.T) {
|
t.Run("Should be the minimum length or 4, whichever is less", func(t *testing.T) {
|
||||||
password1 := GeneratePassword(5)
|
password1 := GeneratePassword(5)
|
||||||
@@ -372,4 +374,10 @@ func TestGeneratePassword(t *testing.T) {
|
|||||||
assert.Contains(t, []rune(passwordLowerCaseLetters), []rune(password)[2])
|
assert.Contains(t, []rune(passwordLowerCaseLetters), []rune(password)[2])
|
||||||
assert.Contains(t, []rune(passwordSpecialChars), []rune(password)[3])
|
assert.Contains(t, []rune(passwordSpecialChars), []rune(password)[3])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should not fail on concurrent calls", func(t *testing.T) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
go GeneratePassword(10)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user