diff --git a/common/parser.go b/common/parser.go
index d94a8e27..37827e45 100644
--- a/common/parser.go
+++ b/common/parser.go
@@ -4,10 +4,8 @@ import (
"bytes"
//"fmt"
//"log"
- "encoding/json"
- "io/ioutil"
+
"net/url"
- "os"
"path/filepath"
"regexp"
"strconv"
@@ -45,6 +43,7 @@ var attachOpen = []byte("Attachment")
var sidParam = []byte("?sid=")
var stypeParam = []byte("&stype=")
+
/*var textShortOpen = []byte("View / Download")*/
@@ -71,13 +70,8 @@ type emojiHolder struct {
}
func InitEmoji() error {
- data, err := ioutil.ReadFile("./config/emoji_default.json")
- if err != nil {
- return err
- }
-
var emoji emojiHolder
- err = json.Unmarshal(data, &emoji)
+ err := unmarshalJsonFile("./config/emoji_default.json", &emoji)
if err != nil {
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{}
- err = json.Unmarshal(data, &emoji)
+ err = unmarshalJsonFileIgnore404("./config/emoji.json", &emoji)
if err != nil {
return err
}
@@ -484,14 +471,14 @@ func (ps *ParseSettings) CopyPtr() *ParseSettings {
}
func ParseMessage(msg string, sectionID int, sectionType string, settings *ParseSettings, user *User) string {
- msg, _ = ParseMessage2(msg,sectionID,sectionType,settings,user)
+ msg, _ = ParseMessage2(msg, sectionID, sectionType, settings, user)
return msg
}
// TODO: Write a test for this
// TODO: We need a lot more hooks here. E.g. To add custom media types and handlers.
// TODO: Use templates to reduce the amount of boilerplate?
-func ParseMessage2(msg string, sectionID int, sectionType string, settings *ParseSettings, user *User) (string,bool) {
+func ParseMessage2(msg string, sectionID int, sectionType string, settings *ParseSettings, user *User) (string, bool) {
if settings == nil {
settings = DefaultParseSettings
}
@@ -1095,7 +1082,7 @@ func parseMediaString(data string, settings *ParseSettings) (media MediaEmbed, o
vid, err := strconv.ParseInt(strings.TrimPrefix(path, "/watch/sm"), 10, 64)
if err == nil {
media.Type = ERawExternal
- media.Body = ""
+ media.Body = ""
return media, true
}
}
diff --git a/common/utils.go b/common/utils.go
index 49be76c6..db48df58 100644
--- a/common/utils.go
+++ b/common/utils.go
@@ -10,9 +10,11 @@ import (
"crypto/rand"
"encoding/base32"
"encoding/base64"
+ "encoding/json"
"errors"
"fmt"
"html"
+ "io/ioutil"
"math"
"os"
"strconv"
@@ -161,11 +163,12 @@ func RelativeTimeBytes(t time.Time, lang int) []byte {
}
*/
-var pMs = 1000;
-var pSec = pMs * 1000;
-var pMin = pSec * 60;
-var pHour = pMin * 60;
-var pDay = pHour * 24;
+var pMs = 1000
+var pSec = pMs * 1000
+var pMin = pSec * 60
+var pHour = pMin * 60
+var pDay = pHour * 24
+
func ConvertPerfUnit(quan float64) (out float64, unit string) {
f := func() (float64, string) {
switch {
@@ -186,7 +189,6 @@ func ConvertPerfUnit(quan float64) (out float64, unit string) {
return math.Ceil(out), unit
}
-
// TODO: Write a test for this
func ConvertByteUnit(bytes float64) (float64, string) {
switch {
@@ -341,7 +343,7 @@ func NameToSlug(name string) (slug string) {
func HasSuspiciousEmail(email string) bool {
lowEmail := strings.ToLower(email)
// TODO: Use a more flexible blacklist, perhaps with a similar mechanism to the HTML tag registration system in PreparseMessage()
- if !strings.Contains(lowEmail,"@") || strings.Contains(lowEmail, "casino") || strings.Contains(lowEmail, "viagra") || strings.Contains(lowEmail, "pharma") || strings.Contains(lowEmail, "pill") {
+ if !strings.Contains(lowEmail, "@") || strings.Contains(lowEmail, "casino") || strings.Contains(lowEmail, "viagra") || strings.Contains(lowEmail, "pharma") || strings.Contains(lowEmail, "pill") {
return true
}
@@ -361,36 +363,113 @@ func HasSuspiciousEmail(email string) bool {
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)
+ if err != nil {
+ return err
+ }
+ return json.Unmarshal(data, in)
+}
+
+func unmarshalJsonFileIgnore404(name string, in interface{}) error {
+ data, err := ioutil.ReadFile(name)
+ if err == os.ErrPermission || err == os.ErrClosed {
+ return err
+ } else if err != nil {
+ 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++
+ }
+
+ 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
+}
+
+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 errors.New("You didn't put in a password.")
+ return ErrWeakPasswordNone
case len(password) < 8:
- return errors.New("Your password needs to be at-least eight characters long")
- case strings.Contains(lowPassword, strings.ToLower(username)) && len(username) > 3:
- return errors.New("You can't use your username in your password.")
- case email != "" && strings.Contains(lowPassword, strings.ToLower(email)):
- return errors.New("You can't use your email in your password.")
+ 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) {
- s := "You may not have "
- for i, passBit := range weakPassStrings {
- if i > 0 {
- if i == len(weakPassStrings)-1 {
- s += " or "
- } else {
- s += ", "
- }
- }
- s += "'" + passBit + "'"
- }
- return errors.New(s + " in your password")
+ 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 {
- return errors.New("You don't have any uppercase characters in your password")
+ return ErrWeakPasswordNoUpper
}
if lower == 0 {
- return errors.New("You don't have any lowercase characters in your password")
+ return ErrWeakPasswordNoLower
}
if len(password) < 18 {
+ if numbers == 0 {
+ return ErrWeakPasswordNoNumbers
+ }
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) {
// 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
}
@@ -441,11 +520,11 @@ func WeakPassword(password, username, email string) error {
// TODO: Write a test for this
func CanonEmail(email string) string {
email = strings.ToLower(email)
-
+
// Gmail emails are equivalent without the dots
espl := strings.Split(email, "@")
if len(espl) >= 2 && espl[1] == "gmail.com" {
- return strings.Replace(espl[0],".","",-1) + "@" + espl[1]
+ return strings.Replace(espl[0], ".", "", -1) + "@" + espl[1]
}
return email
diff --git a/main.go b/main.go
index 9e509b55..1c406a2c 100644
--- a/main.go
+++ b/main.go
@@ -159,6 +159,9 @@ func storeInit() (err error) {
if err = c.InitEmoji(); err != nil {
return errors.WithStack(err)
}
+ if err = c.InitWeakPasswords(); err != nil {
+ return errors.WithStack(err)
+ }
log.Print("Loading the static files.")
if err = c.Themes.LoadStaticFiles(); err != nil {
diff --git a/misc_test.go b/misc_test.go
index af3807a1..952bb1aa 100644
--- a/misc_test.go
+++ b/misc_test.go
@@ -2,7 +2,6 @@ package main
import (
"bytes"
- "strings"
"database/sql"
"fmt"
"io/ioutil"
@@ -10,12 +9,14 @@ import (
"os"
"runtime/debug"
"strconv"
+ "strings"
"testing"
"time"
c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/gauth"
"github.com/Azareal/Gosora/common/phrases"
+ "github.com/pkg/errors"
)
func miscinit(t *testing.T) {
@@ -2002,26 +2003,85 @@ func TestWidgets(t *testing.T) {
func TestUtils(t *testing.T) {
email := "test@example.com"
cemail := c.CanonEmail(email)
- expect(t,cemail==email,fmt.Sprintf("%s should be %s", cemail, email))
+ expect(t, cemail == email, fmt.Sprintf("%s should be %s", cemail, email))
email = "test.test@example.com"
cemail = c.CanonEmail(email)
- expect(t,cemail==email,fmt.Sprintf("%s should be %s", cemail, email))
+ expect(t, cemail == email, fmt.Sprintf("%s should be %s", cemail, email))
email = "test.test@gmail.com"
eemail := "testtest@gmail.com"
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@gmail.com"
eemail = "testtest@gmail.com"
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"
lowEmail := strings.ToLower(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
}