make it easier to define weak password definitions
add tests for weak passwords make it easier to check values of errors returned from weak password loosen weak password requirements for long passwords reduce boilerplate when loading json files only check for email in passwords when it is longer than two chars more canonemail tests
This commit is contained in:
parent
0254687d5b
commit
f0c9544af6
|
@ -4,10 +4,8 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
//"fmt"
|
//"fmt"
|
||||||
//"log"
|
//"log"
|
||||||
"encoding/json"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -45,6 +43,7 @@ var attachOpen = []byte("<a class='attach'href=\"")
|
||||||
var attachClose = []byte("\"download>Attachment</a>")
|
var attachClose = []byte("\"download>Attachment</a>")
|
||||||
var sidParam = []byte("?sid=")
|
var sidParam = []byte("?sid=")
|
||||||
var stypeParam = []byte("&stype=")
|
var stypeParam = []byte("&stype=")
|
||||||
|
|
||||||
/*var textShortOpen = []byte("<a class='attach'href=\"")
|
/*var textShortOpen = []byte("<a class='attach'href=\"")
|
||||||
var textShortOpen2 = []byte("\">View</a> / <a class='attach'href=\"")
|
var textShortOpen2 = []byte("\">View</a> / <a class='attach'href=\"")
|
||||||
var textShortClose = []byte("\"download>Download</a>")*/
|
var textShortClose = []byte("\"download>Download</a>")*/
|
||||||
|
@ -71,13 +70,8 @@ type emojiHolder struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitEmoji() error {
|
func InitEmoji() error {
|
||||||
data, err := ioutil.ReadFile("./config/emoji_default.json")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var emoji emojiHolder
|
var emoji emojiHolder
|
||||||
err = json.Unmarshal(data, &emoji)
|
err := unmarshalJsonFile("./config/emoji_default.json", &emoji)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -89,15 +83,8 @@ func InitEmoji() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err = ioutil.ReadFile("./config/emoji.json")
|
|
||||||
if err == os.ErrPermission || err == os.ErrClosed {
|
|
||||||
return err
|
|
||||||
} else if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
emoji = emojiHolder{}
|
emoji = emojiHolder{}
|
||||||
err = json.Unmarshal(data, &emoji)
|
err = unmarshalJsonFileIgnore404("./config/emoji.json", &emoji)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
139
common/utils.go
139
common/utils.go
|
@ -10,9 +10,11 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -161,11 +163,12 @@ func RelativeTimeBytes(t time.Time, lang int) []byte {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var pMs = 1000;
|
var pMs = 1000
|
||||||
var pSec = pMs * 1000;
|
var pSec = pMs * 1000
|
||||||
var pMin = pSec * 60;
|
var pMin = pSec * 60
|
||||||
var pHour = pMin * 60;
|
var pHour = pMin * 60
|
||||||
var pDay = pHour * 24;
|
var pDay = pHour * 24
|
||||||
|
|
||||||
func ConvertPerfUnit(quan float64) (out float64, unit string) {
|
func ConvertPerfUnit(quan float64) (out float64, unit string) {
|
||||||
f := func() (float64, string) {
|
f := func() (float64, string) {
|
||||||
switch {
|
switch {
|
||||||
|
@ -186,7 +189,6 @@ func ConvertPerfUnit(quan float64) (out float64, unit string) {
|
||||||
return math.Ceil(out), unit
|
return math.Ceil(out), unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Write a test for this
|
// TODO: Write a test for this
|
||||||
func ConvertByteUnit(bytes float64) (float64, string) {
|
func ConvertByteUnit(bytes float64) (float64, string) {
|
||||||
switch {
|
switch {
|
||||||
|
@ -361,24 +363,63 @@ func HasSuspiciousEmail(email string) bool {
|
||||||
return dotCount > 7 || shortBits > 2
|
return dotCount > 7 || shortBits > 2
|
||||||
}
|
}
|
||||||
|
|
||||||
var weakPassStrings = []string{"test", "123", "6969", "password", "qwerty", "fuck", "love"}
|
func unmarshalJsonFile(name string, in interface{}) error {
|
||||||
|
data, err := ioutil.ReadFile(name)
|
||||||
// TODO: Write a test for this
|
if err != nil {
|
||||||
func WeakPassword(password, username, email string) error {
|
return err
|
||||||
lowPassword := strings.ToLower(password)
|
}
|
||||||
switch {
|
return json.Unmarshal(data, in)
|
||||||
case password == "":
|
}
|
||||||
return errors.New("You didn't put in a password.")
|
|
||||||
case len(password) < 8:
|
func unmarshalJsonFileIgnore404(name string, in interface{}) error {
|
||||||
return errors.New("Your password needs to be at-least eight characters long")
|
data, err := ioutil.ReadFile(name)
|
||||||
case strings.Contains(lowPassword, strings.ToLower(username)) && len(username) > 3:
|
if err == os.ErrPermission || err == os.ErrClosed {
|
||||||
return errors.New("You can't use your username in your password.")
|
return err
|
||||||
case email != "" && strings.Contains(lowPassword, strings.ToLower(email)):
|
} else if err != nil {
|
||||||
return errors.New("You can't use your email in your password.")
|
return nil
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
type weakpassHolder struct {
|
||||||
|
Contains []string `json:"contains"`
|
||||||
|
Literal []string `json:"literal"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitWeakPasswords() error {
|
||||||
|
var weakpass weakpassHolder
|
||||||
|
err := unmarshalJsonFile("./config/weakpass_default.json", &weakpass)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
wcon := make(map[string]struct{})
|
||||||
|
for _, item := range weakpass.Contains {
|
||||||
|
wcon[item] = struct{}{}
|
||||||
|
}
|
||||||
|
for _, item := range weakpass.Literal {
|
||||||
|
weakPassLit[item] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
weakpass = weakpassHolder{}
|
||||||
|
err = unmarshalJsonFileIgnore404("./config/weakpass.json", &weakpass)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
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++
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, passBit := range weakPassStrings {
|
|
||||||
if strings.Contains(lowPassword, passBit) {
|
|
||||||
s := "You may not have "
|
s := "You may not have "
|
||||||
for i, passBit := range weakPassStrings {
|
for i, passBit := range weakPassStrings {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
|
@ -390,7 +431,45 @@ func WeakPassword(password, username, email string) error {
|
||||||
}
|
}
|
||||||
s += "'" + passBit + "'"
|
s += "'" + passBit + "'"
|
||||||
}
|
}
|
||||||
return errors.New(s + " in your password")
|
ErrWeakPasswordContains = errors.New(s + " in your password")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// TODO: Write a test for this
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := weakPassLit[lowPassword]
|
||||||
|
if ok {
|
||||||
|
return ErrWeakPasswordCommon
|
||||||
|
}
|
||||||
|
for _, passBit := range weakPassStrings {
|
||||||
|
if strings.Contains(lowPassword, passBit) {
|
||||||
|
return ErrWeakPasswordContains
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,22 +497,22 @@ func WeakPassword(password, username, email string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if numbers == 0 {
|
|
||||||
return errors.New("You don't have any numbers in your password")
|
|
||||||
}
|
|
||||||
if upper == 0 {
|
if upper == 0 {
|
||||||
return errors.New("You don't have any uppercase characters in your password")
|
return ErrWeakPasswordNoUpper
|
||||||
}
|
}
|
||||||
if lower == 0 {
|
if lower == 0 {
|
||||||
return errors.New("You don't have any lowercase characters in your password")
|
return ErrWeakPasswordNoLower
|
||||||
}
|
}
|
||||||
if len(password) < 18 {
|
if len(password) < 18 {
|
||||||
|
if numbers == 0 {
|
||||||
|
return ErrWeakPasswordNoNumbers
|
||||||
|
}
|
||||||
if (len(password) / 2) > len(charMap) {
|
if (len(password) / 2) > len(charMap) {
|
||||||
return errors.New("You don't have enough unique characters in your password")
|
return ErrWeakPasswordUniqueChars
|
||||||
}
|
}
|
||||||
} else if (len(password) / 3) > len(charMap) {
|
} else if (len(password) / 3) > len(charMap) {
|
||||||
// Be a little lenient on the number of unique characters for long passwords
|
// Be a little lenient on the number of unique characters for long passwords
|
||||||
return errors.New("You don't have enough unique characters in your password")
|
return ErrWeakPasswordUniqueChars
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
3
main.go
3
main.go
|
@ -159,6 +159,9 @@ func storeInit() (err error) {
|
||||||
if err = c.InitEmoji(); err != nil {
|
if err = c.InitEmoji(); err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
if err = c.InitWeakPasswords(); err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
log.Print("Loading the static files.")
|
log.Print("Loading the static files.")
|
||||||
if err = c.Themes.LoadStaticFiles(); err != nil {
|
if err = c.Themes.LoadStaticFiles(); err != nil {
|
||||||
|
|
62
misc_test.go
62
misc_test.go
|
@ -2,7 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -10,12 +9,14 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
"github.com/Azareal/Gosora/common/gauth"
|
"github.com/Azareal/Gosora/common/gauth"
|
||||||
"github.com/Azareal/Gosora/common/phrases"
|
"github.com/Azareal/Gosora/common/phrases"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func miscinit(t *testing.T) {
|
func miscinit(t *testing.T) {
|
||||||
|
@ -2017,11 +2018,70 @@ func TestUtils(t *testing.T) {
|
||||||
cemail = c.CanonEmail(email)
|
cemail = c.CanonEmail(email)
|
||||||
expect(t, cemail == eemail, fmt.Sprintf("%s should be %s", cemail, eemail))
|
expect(t, cemail == eemail, fmt.Sprintf("%s should be %s", cemail, eemail))
|
||||||
|
|
||||||
|
email = "test.TEST.test@gmail.com"
|
||||||
|
eemail = "testtesttest@gmail.com"
|
||||||
|
cemail = c.CanonEmail(email)
|
||||||
|
expect(t, cemail == eemail, fmt.Sprintf("%s should be %s", cemail, eemail))
|
||||||
|
|
||||||
|
email = "test..TEST.test@gmail.com"
|
||||||
|
eemail = "testtesttest@gmail.com"
|
||||||
|
cemail = c.CanonEmail(email)
|
||||||
|
expect(t, cemail == eemail, fmt.Sprintf("%s should be %s", cemail, eemail))
|
||||||
|
|
||||||
email = "TEST.test@example.com"
|
email = "TEST.test@example.com"
|
||||||
lowEmail := strings.ToLower(email)
|
lowEmail := strings.ToLower(email)
|
||||||
cemail = c.CanonEmail(email)
|
cemail = c.CanonEmail(email)
|
||||||
expect(t, cemail == lowEmail, fmt.Sprintf("%s should be %s", cemail, lowEmail))
|
expect(t, cemail == lowEmail, fmt.Sprintf("%s should be %s", cemail, lowEmail))
|
||||||
|
|
||||||
|
email = "test.TEST.test@example.com"
|
||||||
|
lowEmail = strings.ToLower(email)
|
||||||
|
cemail = c.CanonEmail(email)
|
||||||
|
expect(t, cemail == lowEmail, fmt.Sprintf("%s should be %s", cemail, lowEmail))
|
||||||
|
|
||||||
|
/*weakPass := func(password, username, email string) func(error,string,...interface{}) {
|
||||||
|
err := c.WeakPassword(password, username, email)
|
||||||
|
return func(expectErr error, m string, p ...interface{}) {
|
||||||
|
m = fmt.Sprintf("pass=%s, user=%s, email=%s ", password, username, email) + m
|
||||||
|
expect(t, err == expectErr, fmt.Sprintf(m,p...))
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
nilErrStr := func(e error) error {
|
||||||
|
if e == nil {
|
||||||
|
e = errors.New("nil")
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
weakPass := func(password, username, email string) func(error) {
|
||||||
|
err := c.WeakPassword(password, username, email)
|
||||||
|
e := nilErrStr(err)
|
||||||
|
m := fmt.Sprintf("pass=%s, user=%s, email=%s ", password, username, email)
|
||||||
|
return func(expectErr error) {
|
||||||
|
ee := nilErrStr(expectErr)
|
||||||
|
expect(t, err == expectErr, m+fmt.Sprintf("err should be '%s' not '%s'", ee, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//weakPass("test", "test", "test@example.com")(c.ErrWeakPasswordContains,"err should be ErrWeakPasswordContains not '%s'")
|
||||||
|
weakPass("", "draw", "test@example.com")(c.ErrWeakPasswordNone)
|
||||||
|
weakPass("test", "draw", "test@example.com")(c.ErrWeakPasswordShort)
|
||||||
|
weakPass("testtest", "draw", "test@example.com")(c.ErrWeakPasswordContains)
|
||||||
|
weakPass("testdraw", "draw", "test@example.com")(c.ErrWeakPasswordNameInPass)
|
||||||
|
weakPass("test@example.com", "draw", "test@example.com")(c.ErrWeakPasswordEmailInPass)
|
||||||
|
weakPass("meet@example.com2", "draw", "")(c.ErrWeakPasswordNoUpper)
|
||||||
|
weakPass("Meet@example.com2", "draw", "")(nil)
|
||||||
|
weakPass("test2", "draw", "test@example.com")(c.ErrWeakPasswordShort)
|
||||||
|
weakPass("test22222222", "draw", "test@example.com")(c.ErrWeakPasswordContains)
|
||||||
|
weakPass("superman", "draw", "test@example.com")(c.ErrWeakPasswordCommon)
|
||||||
|
weakPass("K\\@<^s}1", "draw", "test@example.com")(nil)
|
||||||
|
weakPass("K\\@<^s}r", "draw", "test@example.com")(c.ErrWeakPasswordNoNumbers)
|
||||||
|
weakPass("k\\@<^s}1", "draw", "test@example.com")(c.ErrWeakPasswordNoUpper)
|
||||||
|
weakPass("aaaaaaaa", "draw", "test@example.com")(c.ErrWeakPasswordNoUpper)
|
||||||
|
weakPass("aA1aA1aA1", "draw", "test@example.com")(c.ErrWeakPasswordUniqueChars)
|
||||||
|
weakPass("abababab", "draw", "test@example.com")(c.ErrWeakPasswordNoUpper)
|
||||||
|
weakPass("11111111111111111111", "draw", "test@example.com")(c.ErrWeakPasswordNoUpper)
|
||||||
|
weakPass("aaaaaaaaaaAAAAAAAAAA", "draw", "test@example.com")(c.ErrWeakPasswordUniqueChars)
|
||||||
|
weakPass("-:u/nMxb,A!n=B;H\\sjM", "draw", "test@example.com")(nil)
|
||||||
|
|
||||||
// TODO: More utils.go tests
|
// TODO: More utils.go tests
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue