gosora/common/weak_passwords.go
Azareal c60118e7c4 WIP forum action code. Currently disabled.
Add Http Conn Count tracking.
Move more panel phrases into the panel namespace.
Use a string builder in hookgen.
Use Countf() in a couple of places to eliminate boilerplate.
Reduce prepared stmt boilerplate in forum store with a lambda.
Reduce prepared stmt boilerplate in topic.go with a lambda.
Reduce prepared stmt boilerplate in group.go with a lambda.
Add TestSetCreatedAt method to *Topic.
Add DateOlderThanQ method to *accDeleteBuilder and *accUpdateBuilder.
Add Stmt method to *accUpdateBuilder and *AccSelectBuilder.
Add AccBuilder interface.
Shorten variable names.
Shorten extractPerm name to ep.
Add avatar_visibility setting stub. Implementation coming in a later commit.
Don't set an IP for installer generated posts.

Add counters_perf_tick_row hook.

Add avatar_visibility phrase.
Add avatar_visibility_label phrase.
Rename forums_no_description to forums_no_desc.
Rename panel.forums_create_description_label to panel.forums_create_desc_label.
Rename panel.forums_create_description to panel.forums_create_desc.
Rename panel_forum_description to panel.forum_desc.
Rename panel_forum_description_placeholder to panel.forum_desc_placeholder.
Add panel_debug_http_conns_label phrase.
Add panel.forum_actions_head phrase.
Add panel.forum_actions_create_head phrase.
Add panel.forum_action_run_on_topic_creation phrase.
Add panel.forum_action_run_days_after_topic_creation phrase.
Add panel.forum_action_run_days_after_topic_last_reply phrase.
Add panel.forum_action_action phrase.
Add panel.forum_action_action_delete phrase.
Add panel.forum_action_action_lock phrase.
Add panel.forum_action_action_unlock phrase.
Add panel.forum_action_action_move phrase.
Add panel.forum_action_extra phrase.
Add panel.forum_action_create_button phrase.

You will need to run the patcher / updater for this commit.
2021-04-08 00:23:11 +10:00

151 lines
3.7 KiB
Go

package common
import (
"errors"
"strconv"
"strings"
"unicode"
)
var weakPassStrings []string
var weakPassLit = make(map[string]struct{})
var ErrWeakPasswordNone = errors.New("You didn't put in a password.")
var ErrWeakPasswordShort = errors.New("Your password needs to be at-least eight characters long")
var ErrWeakPasswordNameInPass = errors.New("You can't use your name in your password.")
var ErrWeakPasswordEmailInPass = errors.New("You can't use your email in your password.")
var ErrWeakPasswordCommon = errors.New("You may not use a password that is in common use")
var ErrWeakPasswordNoNumbers = errors.New("You don't have any numbers in your password")
var ErrWeakPasswordNoUpper = errors.New("You don't have any uppercase characters in your password")
var ErrWeakPasswordNoLower = errors.New("You don't have any lowercase characters in your password")
var ErrWeakPasswordUniqueChars = errors.New("You don't have enough unique characters in your password")
var ErrWeakPasswordContains error
type weakpassHolder struct {
Contains []string `json:"contains"`
Literal []string `json:"literal"`
}
func InitWeakPasswords() error {
var weakpass weakpassHolder
e := unmarshalJsonFile("./config/weakpass_default.json", &weakpass)
if e != nil {
return e
}
wcon := make(map[string]struct{})
for _, item := range weakpass.Contains {
wcon[item] = struct{}{}
}
for _, item := range weakpass.Literal {
weakPassLit[item] = struct{}{}
}
weakpass = weakpassHolder{}
e = unmarshalJsonFileIgnore404("./config/weakpass.json", &weakpass)
if e != nil {
return e
}
for _, item := range weakpass.Contains {
wcon[item] = struct{}{}
}
for _, item := range weakpass.Literal {
weakPassLit[item] = struct{}{}
}
weakPassStrings = make([]string, len(wcon))
var i int
for pattern, _ := range wcon {
weakPassStrings[i] = pattern
i++
}
s := "You may not have "
for i, passBit := range weakPassStrings {
if i > 0 {
if i == len(weakPassStrings)-1 {
s += " or "
} else {
s += ", "
}
}
s += "'" + passBit + "'"
}
ErrWeakPasswordContains = errors.New(s + " in your password")
return nil
}
func WeakPassword(password, username, email string) error {
lowPassword := strings.ToLower(password)
switch {
case password == "":
return ErrWeakPasswordNone
case len(password) < 8:
return ErrWeakPasswordShort
case len(username) > 3 && strings.Contains(lowPassword, strings.ToLower(username)):
return ErrWeakPasswordNameInPass
case len(email) > 2 && strings.Contains(lowPassword, strings.ToLower(email)):
return ErrWeakPasswordEmailInPass
}
if len(lowPassword) > 30 {
return nil
}
litPass := lowPassword
for i := 0; i < 10; i++ {
litPass = strings.TrimSuffix(litPass, strconv.Itoa(i))
}
_, ok := weakPassLit[litPass]
if ok {
return ErrWeakPasswordCommon
}
for _, passBit := range weakPassStrings {
if strings.Contains(lowPassword, passBit) {
return ErrWeakPasswordContains
}
}
charMap := make(map[rune]int)
var numbers, symbols, upper, lower int
for _, char := range password {
charItem, ok := charMap[char]
if ok {
charItem++
} else {
charItem = 1
}
charMap[char] = charItem
if unicode.IsLetter(char) {
if unicode.IsUpper(char) {
upper++
} else {
lower++
}
} else if unicode.IsNumber(char) {
numbers++
} else {
symbols++
}
}
if upper == 0 {
return ErrWeakPasswordNoUpper
}
if lower == 0 {
return ErrWeakPasswordNoLower
}
if len(password) < 18 {
if numbers == 0 {
return ErrWeakPasswordNoNumbers
}
if (len(password) / 2) > len(charMap) {
return ErrWeakPasswordUniqueChars
}
} else if (len(password) / 3) > len(charMap) {
// Be a little lenient on the number of unique characters for long passwords
return ErrWeakPasswordUniqueChars
}
return nil
}