validate 2fa. more cleanups
This commit is contained in:
parent
f3cc9cdeed
commit
b042b4dbc9
32
2fa.go
32
2fa.go
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,7 +18,29 @@ func generate2fa() string {
|
||||||
|
|
||||||
}
|
}
|
||||||
func Validate2FA(u *UserData, challenge string) bool {
|
func Validate2FA(u *UserData, challenge string) bool {
|
||||||
|
defer func() {
|
||||||
|
u.Delete("2fa")
|
||||||
|
u.Delete("2faexpires")
|
||||||
|
}()
|
||||||
|
|
||||||
v, ok := u.Get("2fa")
|
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
|
return ok && v == challenge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,20 +48,19 @@ func Send2FA(u *UserData) error {
|
||||||
code := generate2fa()
|
code := generate2fa()
|
||||||
u.Set("2fa", code)
|
u.Set("2fa", code)
|
||||||
u.Set("2faexpires", fmt.Sprintf("%d", time.Now().Add(15*time.Minute).Unix()))
|
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 {
|
if !ok {
|
||||||
return errors.New("send2fa: no email")
|
return errors.New("send2fa: no email")
|
||||||
}
|
}
|
||||||
firstname,ok:=u.Get("firstname")
|
firstname, ok := u.Get("firstname")
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("send2fa: no firstname")
|
return errors.New("send2fa: no firstname")
|
||||||
}
|
}
|
||||||
lastname,ok:=u.Get("lastname")
|
lastname, ok := u.Get("lastname")
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("send2fa: no lastname")
|
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)
|
return Send2faEmail(email, fullname, code)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
16
emails.go
16
emails.go
|
@ -135,15 +135,15 @@ func SendRecoveryEmail(recipient, username, code string) bool {
|
||||||
|
|
||||||
func Send2faEmail(recipient, fullname, code string) error {
|
func Send2faEmail(recipient, fullname, code string) error {
|
||||||
data := struct {
|
data := struct {
|
||||||
SiteName string
|
SiteName string
|
||||||
FromEmail string
|
FromEmail string
|
||||||
FullName string
|
FullName string
|
||||||
Code string
|
Code string
|
||||||
}{
|
}{
|
||||||
SiteName: c.SiteName,
|
SiteName: c.SiteName,
|
||||||
FromEmail: c.FromEmail,
|
FromEmail: c.FromEmail,
|
||||||
FullName: fullname,
|
FullName: fullname,
|
||||||
Code: code,
|
Code: code,
|
||||||
}
|
}
|
||||||
var body bytes.Buffer
|
var body bytes.Buffer
|
||||||
err := c.Templates.TwoFA.Execute(&body, data)
|
err := c.Templates.TwoFA.Execute(&body, data)
|
||||||
|
|
151
main.go
151
main.go
|
@ -2,7 +2,6 @@ package scsusers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
|
@ -16,7 +15,7 @@ type templates struct {
|
||||||
Registration *template.Template
|
Registration *template.Template
|
||||||
Alert *template.Template
|
Alert *template.Template
|
||||||
Recovery *template.Template
|
Recovery *template.Template
|
||||||
TwoFA *template.Template
|
TwoFA *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
|
@ -119,7 +118,6 @@ func NewUser() *UserData {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Get(username string) (*UserData, bool) {
|
func Get(username string) (*UserData, bool) {
|
||||||
|
|
||||||
u := NewUser()
|
u := NewUser()
|
||||||
q := fmt.Sprintf("select username, password, id from %s_auth where username=?", c.TablePrefix)
|
q := fmt.Sprintf("select username, password, id from %s_auth where username=?", c.TablePrefix)
|
||||||
err := c.db.Get(u, q, username)
|
err := c.db.Get(u, q, username)
|
||||||
|
@ -145,39 +143,6 @@ func Get(username string) (*UserData, bool) {
|
||||||
return u, true
|
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 {
|
func GetUserid(username string) int64 {
|
||||||
var i int64
|
var i int64
|
||||||
username = strings.ToLower(username)
|
username = strings.ToLower(username)
|
||||||
|
@ -190,117 +155,3 @@ func GetUserid(username string) int64 {
|
||||||
}
|
}
|
||||||
return i
|
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue