diff options
author | Maxim Tkachenko <maxim.tkachenko@gmail.com> | 2019-10-14 22:24:26 +0700 |
---|---|---|
committer | zeripath <art27@cantab.net> | 2019-10-14 16:24:26 +0100 |
commit | db657192d0349f7b10a62515fbf085d3a48d88f9 (patch) | |
tree | d298b9b2c487af61dc399774e67dcb3440add9c2 /modules | |
parent | f9aba9ba0f07b77cb46dde6eda3c3f5b8fa841fe (diff) | |
download | gitea-db657192d0349f7b10a62515fbf085d3a48d88f9.tar.gz gitea-db657192d0349f7b10a62515fbf085d3a48d88f9.zip |
Password Complexity Checks (#6230)
Add password complexity checks. The default settings require a lowercase, uppercase, number and a special character within passwords.
Co-Authored-By: T-M-A <maxim.tkachenko@gmail.com>
Co-Authored-By: Lanre Adelowo <adelowomailbox@gmail.com>
Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com>
Co-Authored-By: Lauris BH <lauris@nix.lv>
Diffstat (limited to 'modules')
-rw-r--r-- | modules/password/password.go | 73 | ||||
-rw-r--r-- | modules/setting/setting.go | 22 |
2 files changed, 95 insertions, 0 deletions
diff --git a/modules/password/password.go b/modules/password/password.go new file mode 100644 index 0000000000..54131b9641 --- /dev/null +++ b/modules/password/password.go @@ -0,0 +1,73 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package password + +import ( + "crypto/rand" + "math/big" + "regexp" + "sync" + + "code.gitea.io/gitea/modules/setting" +) + +var matchComplexities = map[string]regexp.Regexp{} +var matchComplexityOnce sync.Once +var validChars string +var validComplexities = map[string]string{ + "lower": "abcdefghijklmnopqrstuvwxyz", + "upper": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "digit": "0123456789", + "spec": `][ !"#$%&'()*+,./:;<=>?@\^_{|}~` + "`-", +} + +// NewComplexity for preparation +func NewComplexity() { + matchComplexityOnce.Do(func() { + if len(setting.PasswordComplexity) > 0 { + for key, val := range setting.PasswordComplexity { + matchComplexity := regexp.MustCompile(val) + matchComplexities[key] = *matchComplexity + validChars += validComplexities[key] + } + } else { + for _, val := range validComplexities { + validChars += val + } + } + }) +} + +// IsComplexEnough return True if password is Complexity +func IsComplexEnough(pwd string) bool { + if len(setting.PasswordComplexity) > 0 { + NewComplexity() + for _, val := range matchComplexities { + if !val.MatchString(pwd) { + return false + } + } + } + return true +} + +// Generate a random password +func Generate(n int) (string, error) { + NewComplexity() + buffer := make([]byte, n) + max := big.NewInt(int64(len(validChars))) + for { + for j := 0; j < n; j++ { + rnd, err := rand.Int(rand.Reader, max) + if err != nil { + return "", err + } + buffer[j] = validChars[rnd.Int64()] + } + if IsComplexEnough(string(buffer)) && string(buffer[0]) != " " && string(buffer[n-1]) != " " { + return string(buffer), nil + } + } +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 8c61bdbb77..278ed4b107 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -146,6 +146,7 @@ var ( MinPasswordLength int ImportLocalPaths bool DisableGitHooks bool + PasswordComplexity map[string]string PasswordHashAlgo string // UI settings @@ -774,6 +775,27 @@ func NewContext() { InternalToken = loadInternalToken(sec) + var dictPC = map[string]string{ + "lower": "[a-z]+", + "upper": "[A-Z]+", + "digit": "[0-9]+", + "spec": `][ !"#$%&'()*+,./:;<=>?@\\^_{|}~` + "`-", + } + PasswordComplexity = make(map[string]string) + cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",") + for _, y := range cfgdata { + ts := strings.TrimSpace(y) + for a := range dictPC { + if strings.ToLower(ts) == a { + PasswordComplexity[ts] = dictPC[ts] + break + } + } + } + if len(PasswordComplexity) == 0 { + PasswordComplexity = dictPC + } + sec = Cfg.Section("attachment") AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments")) if !filepath.IsAbs(AttachmentPath) { |