170 lines
No EOL
4.3 KiB
Go
170 lines
No EOL
4.3 KiB
Go
package user
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"log"
|
|
"math/rand"
|
|
"github.com/jmoiron/sqlx"
|
|
)
|
|
|
|
type UserClient interface {
|
|
register(username, password, email string) (bool, error)
|
|
login(username, password string, requiredMailValidation bool) (bool, error)
|
|
getMailValidationToken(email string, forceRecreate bool) (string, error)
|
|
}
|
|
|
|
type UserClientMemory struct {
|
|
users map[string]string
|
|
}
|
|
|
|
func GetUserMemmoryClient() *UserClientMemory {
|
|
uc := UserClientMemory{}
|
|
uc.users = make(map[string]string)
|
|
uc.users["admin"]="password"
|
|
return &uc
|
|
}
|
|
|
|
func (uc *UserClientMemory) register(username, password, email string) (bool, error) {
|
|
if _, ok := uc.users[username]; ok {
|
|
return false, errors.New("Username already used")
|
|
}
|
|
|
|
uc.users[username] = password
|
|
return true, nil
|
|
}
|
|
|
|
func (uc UserClientMemory) login(username, password string, requiredMailValidation bool) (bool, error) {
|
|
if requiredMailValidation == true {
|
|
return false, errors.New("In memmory User Client cant validate email addresses")
|
|
}
|
|
if val, ok := uc.users[username]; ok {
|
|
fmt.Println("Login for valide user")
|
|
if val == password {
|
|
return true, nil
|
|
}
|
|
} else {
|
|
fmt.Printf("User %v not found", username)
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
func (uc UserClientMemory) getMailValidationToken(email string, forceRecreate bool) (string, error) {
|
|
token := randomString(35)
|
|
token = fmt.Sprintf("%v/%v", base64.StdEncoding.EncodeToString([]byte(email)), token)
|
|
return token, nil
|
|
}
|
|
|
|
|
|
|
|
type UserClientSql struct {
|
|
db *sqlx.DB
|
|
}
|
|
|
|
type User struct {
|
|
Id int `db:"id"`
|
|
Mail string `db:"mail"`
|
|
MailValidationCode *string `db:"mailValidationCode"`
|
|
MailValidate bool `db:"mailValidate"`
|
|
Username string `db:"username"`
|
|
Password string `db:"password"`
|
|
|
|
}
|
|
|
|
func NewUserClientSql(DB *sqlx.DB) *UserClientSql {
|
|
uc := UserClientSql{}
|
|
uc.db = DB
|
|
return &uc
|
|
}
|
|
|
|
func (uc *UserClientSql) register(username, password, email string) (bool, error) {
|
|
_, err := uc.db.NamedExec("INSERT INTO `user` (`mail`, `username`, `password`) VALUE (:mail, :username, :password)", map[string]interface{}{
|
|
"mail": email,
|
|
"username": username,
|
|
"password": uc.hashAndSalt([]byte(password)),
|
|
})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (uc UserClientSql) login(username, password string, requiredMailValidation bool) (bool, error) {
|
|
user := User{}
|
|
err := uc.db.Get(&user, "SELECT * FROM `user` WHERE `username` = ?", username)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if uc.comparePasswords(user.Password, []byte(password)) == false {
|
|
return false, errors.New("Wrong password")
|
|
}
|
|
|
|
if requiredMailValidation && user.MailValidate == false {
|
|
return false, errors.New("Mail not validated")
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
func (uc UserClientSql) getMailValidationToken(email string, forceRecreate bool) (string, error) {
|
|
user := User{}
|
|
err := uc.db.Get(&user, "SELECT * FROM `user` WHERE `mail` = ?", email)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if user.MailValidationCode != nil && forceRecreate == false {
|
|
return *user.MailValidationCode, nil
|
|
}
|
|
token := randomString(25)
|
|
_, err = uc.db.NamedExec("UPDATE `user` SET `mailValidationCode` = :code WHERE `mail` = :mail LIMIT 1", map[string]interface{}{
|
|
"code": token,
|
|
"mail": email,
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
//token = fmt.Sprintf("%v/%v", base64.StdEncoding.EncodeToString([]byte(email)), token)
|
|
return token, nil
|
|
}
|
|
|
|
func (uc UserClientSql)hashAndSalt(pwd []byte) string {
|
|
|
|
// Use GenerateFromPassword to hash & salt pwd.
|
|
// MinCost is just an integer constant provided by the bcrypt
|
|
// package along with DefaultCost & MaxCost.
|
|
// The cost can be any value you want provided it isn't lower
|
|
// than the MinCost (4)
|
|
hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.MinCost)
|
|
if err != nil {
|
|
log.Println(err)
|
|
} // GenerateFromPassword returns a byte slice so we need to
|
|
// convert the bytes to a string and return it
|
|
return string(hash)
|
|
}
|
|
|
|
func (uc UserClientSql)comparePasswords(hashedPwd string, plainPwd []byte) bool {
|
|
byteHash := []byte(hashedPwd)
|
|
|
|
err := bcrypt.CompareHashAndPassword(byteHash, plainPwd)
|
|
if err != nil {
|
|
log.Println(err)
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
|
|
|
|
func randomString(n int) string {
|
|
var letters = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|
b := make([]byte, n)
|
|
for i := range b {
|
|
b[i] = letters[rand.Intn(len(letters))]
|
|
}
|
|
return string(b)
|
|
} |