diff --git a/2fa.go b/2fa.go index f027edb..9f01572 100644 --- a/2fa.go +++ b/2fa.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "strconv" "time" ) @@ -17,7 +18,29 @@ func generate2fa() string { } func Validate2FA(u *UserData, challenge string) bool { + defer func() { + u.Delete("2fa") + u.Delete("2faexpires") + }() + v, ok := u.Get("2fa") + if !ok { + return false + } + + exp, ok := u.Get("2faexpires") + if !ok { + + return false + } + tmp, err := strconv.ParseInt(exp, 10, 64) + if err != nil { + return false + } + if int64(time.Now().Unix()) > tmp { + return false + + } return ok && v == challenge } @@ -25,20 +48,19 @@ func Send2FA(u *UserData) error { code := generate2fa() u.Set("2fa", code) u.Set("2faexpires", fmt.Sprintf("%d", time.Now().Add(15*time.Minute).Unix())) - email,ok:=u.Get("email") + email, ok := u.Get("email") if !ok { return errors.New("send2fa: no email") } - firstname,ok:=u.Get("firstname") + firstname, ok := u.Get("firstname") if !ok { return errors.New("send2fa: no firstname") } - lastname,ok:=u.Get("lastname") + lastname, ok := u.Get("lastname") if !ok { return errors.New("send2fa: no lastname") } - fullname:=fmt.Sprintf("%s %s", firstname, lastname) + fullname := fmt.Sprintf("%s %s", firstname, lastname) return Send2faEmail(email, fullname, code) } - diff --git a/auth.go b/auth.go new file mode 100644 index 0000000..5c446a1 --- /dev/null +++ b/auth.go @@ -0,0 +1,41 @@ +package scsusers + +import ( + "fmt" + "log" + + "golang.org/x/crypto/bcrypt" +) + +func Login(username, password string) bool { + u, ok := Get(username) + if !ok { + return false + } + if bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) != nil { + log.Printf("scsusers.Login: Failed password for " + username) + return false + } + log.Printf("User %s logged in\n", username) + return true +} + +func (u *UserData) ChangePassword(oldpass, newpass string) bool { + if bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(oldpass)) != nil { + log.Printf("scsusers.ChangePassword: Failed password for %s\n", u.Username) + return false + } + newcrypt, err := bcrypt.GenerateFromPassword([]byte(newpass), 10) + if err != nil { + log.Printf("scsusers.ChangePassword: generate: %s", err.Error()) + return false + } + q := fmt.Sprintf("update %s_auth set password=? where userid=?", c.TablePrefix) + _, err = c.db.Exec(q, newcrypt, u.UserID) + if err != nil { + log.Printf("scsusers.ChangePassword: update failed for %s: %s\n", u.Username, err.Error()) + return false + } + return true + +} diff --git a/emails.go b/emails.go index c252b0d..a71c724 100644 --- a/emails.go +++ b/emails.go @@ -135,15 +135,15 @@ func SendRecoveryEmail(recipient, username, code string) bool { func Send2faEmail(recipient, fullname, code string) error { data := struct { - SiteName string - FromEmail string - FullName string - Code string + SiteName string + FromEmail string + FullName string + Code string }{ - SiteName: c.SiteName, - FromEmail: c.FromEmail, - FullName: fullname, - Code: code, + SiteName: c.SiteName, + FromEmail: c.FromEmail, + FullName: fullname, + Code: code, } var body bytes.Buffer err := c.Templates.TwoFA.Execute(&body, data) diff --git a/main.go b/main.go index a6c685d..fe3d0a8 100644 --- a/main.go +++ b/main.go @@ -2,7 +2,6 @@ package scsusers import ( "database/sql" - "encoding/json" "fmt" "html/template" "log" @@ -16,7 +15,7 @@ type templates struct { Registration *template.Template Alert *template.Template Recovery *template.Template - TwoFA *template.Template + TwoFA *template.Template } type config struct { @@ -119,7 +118,6 @@ func NewUser() *UserData { } func Get(username string) (*UserData, bool) { - u := NewUser() q := fmt.Sprintf("select username, password, id from %s_auth where username=?", c.TablePrefix) err := c.db.Get(u, q, username) @@ -145,39 +143,6 @@ func Get(username string) (*UserData, bool) { return u, true } -func Login(username, password string) bool { - u, ok := Get(username) - if !ok { - return false - } - if bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) != nil { - log.Printf("scsusers.Login: Failed password for " + username) - return false - } - log.Printf("User %s logged in\n", username) - return true -} - -func (u *UserData) ChangePassword(oldpass, newpass string) bool { - if bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(oldpass)) != nil { - log.Printf("scsusers.ChangePassword: Failed password for %s\n", u.Username) - return false - } - newcrypt, err := bcrypt.GenerateFromPassword([]byte(newpass), 10) - if err != nil { - log.Printf("scsusers.ChangePassword: generate: %s", err.Error()) - return false - } - q := fmt.Sprintf("update %s_auth set password=? where userid=?", c.TablePrefix) - _, err = c.db.Exec(q, newcrypt, u.UserID) - if err != nil { - log.Printf("scsusers.ChangePassword: update failed for %s: %s\n", u.Username, err.Error()) - return false - } - return true - -} - func GetUserid(username string) int64 { var i int64 username = strings.ToLower(username) @@ -190,117 +155,3 @@ func GetUserid(username string) int64 { } return i } - -func (u *UserData) Get(key string) (string, bool) { - tmp, ok := u.Meta[key] - return tmp.Value, ok -} - -func (u *UserData) Set(key, value string) error { - tmp, ok := u.Meta[key] - if ok { - _, err := c.db.Query(fmt.Sprintf("delete from %s_meta where id=?", c.TablePrefix), tmp.ID) - if err != nil { - log.Printf("scsauth: set: delete: %s", err.Error()) - return err - } - } - var insertid int64 - err := c.db.Get(&insertid, fmt.Sprintf("insert into %s_meta (userid, meta_key, meta_value) VALUES (?,?,?) returning id", c.TablePrefix), u.UserID, key, value) - if err != nil { - log.Printf("scsauth: set: insert: %s", err.Error()) - return err - } - var m metadata - m.Key = key - m.Value = value - m.ID = insertid - u.Meta[key] = m - - return nil -} - -func SaveUser(username string, d UserData) bool { - username = strings.ToLower(username) - q := fmt.Sprintf("update %s_userdata set data=? where username = ?", c.TablePrefix) - j, err := json.Marshal(d) - if err != nil { - log.Printf("scsusers.SaveUser: json.Marshal failed for username %s : %s\n", username, err.Error()) - return false - } - _, err = c.db.Exec(q, username, j) - if err != nil { - log.Printf("scsusers.SaveUser: db.Exec failed for username %s : %s\n", username, err.Error()) - return false - } - return true -} - -type Metadata struct { - MetaKey string `db:"meta_key"` - MetaValue string `db:"meta_value"` -} - -func GetAllMeta(username string) map[string]string { - meta := make(map[string]string) - username = strings.ToLower(username) - - q := fmt.Sprintf(`select meta_key, meta_value - from %s_user_metadata where - user_id=(select userid from %s_auth where username = ?)`, - c.TablePrefix, c.TablePrefix) - rows, err := c.db.Queryx(q, username) - if err != nil && err != sql.ErrNoRows { - log.Printf("scsusers.GetAllMeta: %s: %s\n", username, err.Error()) - return meta - } - var m Metadata - for rows.Next() { - err = rows.StructScan(&m) - if err != nil { - log.Printf("scsusers.GetAllMeta: StructScan: %s: %s\n", username, err.Error()) - return meta - } - meta[m.MetaKey] = m.MetaValue - } - return meta -} - -func GetMeta(username string, metakey string) string { - var v string - username = strings.ToLower(username) - - q := fmt.Sprintf(`select meta_value from %s_user_metadata where - user_id=(select userid from %s_auth where username = ?) AND meta_key=?`, c.TablePrefix, c.TablePrefix) - err := c.db.Get(&v, q, username, metakey) - if err != nil && err != sql.ErrNoRows { - log.Printf("scsusers.GetMeta: %s - %s - %s\n", username, metakey, err.Error()) - } - if v == "" { - // get default user - err := c.db.Get(&v, q, "//default//", metakey) - if err != nil && err != sql.ErrNoRows { - log.Printf("scsusers.GetMeta: %s - %s - %s\n", username, metakey, err.Error()) - } - - } - return v -} - -func SetMeta(username string, metakey string, metavalue string) { - var err error - username = strings.ToLower(username) - - if metavalue == "" { - q := fmt.Sprintf(`delete from %s_user_metadata where user_id=(select userid from %s_auth where username = ?) AND meta_key=?`, - c.TablePrefix, c.TablePrefix) - _, err = c.db.Exec(q, username, metakey) - } else { - q := fmt.Sprintf(`insert into %s_user_metadata (user_id, meta_key, meta_value) VALUES - ((select userid from %s_auth where username = ?), ?, ?)`, c.TablePrefix, c.TablePrefix) - _, err = c.db.Exec(q, username, metakey, metavalue) - } - if err != nil { - log.Printf("scsusers.SetMeta: %s %s %s %s\n", username, metakey, metavalue, err.Error()) - } -} diff --git a/meta.go b/meta.go new file mode 100644 index 0000000..a1205fe --- /dev/null +++ b/meta.go @@ -0,0 +1,50 @@ +package scsusers + +import ( + "fmt" + "log" +) + +type Metadata struct { + MetaKey string `db:"meta_key"` + MetaValue string `db:"meta_value"` +} + +func (u *UserData) Get(key string) (string, bool) { + tmp, ok := u.Meta[key] + return tmp.Value, ok +} + +func (u *UserData) Delete(key string) { + tmp, ok := u.Meta[key] + if ok { + _, err := c.db.Query(fmt.Sprintf("delete from %s_meta where id=?", c.TablePrefix), tmp.ID) + if err != nil { + log.Printf("scsauth: set: delete: %s", err.Error()) + } + } +} + +func (u *UserData) Set(key, value string) error { + tmp, ok := u.Meta[key] + if ok { + _, err := c.db.Query(fmt.Sprintf("delete from %s_meta where id=?", c.TablePrefix), tmp.ID) + if err != nil { + log.Printf("scsauth: set: delete: %s", err.Error()) + return err + } + } + var insertid int64 + err := c.db.Get(&insertid, fmt.Sprintf("insert into %s_meta (userid, meta_key, meta_value) VALUES (?,?,?) returning id", c.TablePrefix), u.UserID, key, value) + if err != nil { + log.Printf("scsauth: set: insert: %s", err.Error()) + return err + } + var m metadata + m.Key = key + m.Value = value + m.ID = insertid + u.Meta[key] = m + + return nil +}