c60118e7c4
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.
151 lines
3.7 KiB
Go
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
|
|
}
|