gogmagog/models/user.go

97 lines
2.6 KiB
Go

package models
import (
"fmt"
"golang.org/x/crypto/bcrypt"
)
// User represents the full DB user field, for inserts and compares.
// No reason to return the hashed pw on the route though.
type User struct {
UserID int64
Username string
DisplayName string
Password []byte
}
// UserNoPassword contains the non password user fields.
// This is preferred outside of the model / store.
type UserNoPassword struct {
UserID int64 `json:"user_id"`
Username string `json:"username"`
DisplayName string `json:"display_name"`
}
// VerifyUserByUsernamePassword returns a single user by the unique username, if the provided password is correct.
func (m *Model) VerifyUserByUsernamePassword(username string, password string) (*UserNoPassword, error) {
user, err := m.SelectUserByUsername(username)
if err != nil {
// throwaway to pad time
hashPassword(username)
return nil, wrapInvalidLogin(err)
}
err = bcrypt.CompareHashAndPassword(user.Password, []byte(password))
if err != nil {
return nil, wrapInvalidLogin(err)
}
return user.NoPassword(), nil
}
// NoPassword strips the user of password.
func (u *User) NoPassword() *UserNoPassword {
return &UserNoPassword{
UserID: u.UserID,
Username: u.Username,
DisplayName: u.DisplayName,
}
}
// CreateUserRequest represents a desired user creation.
type CreateUserRequest struct {
Username string `json:"username"`
DisplayName string `json:"display_name"`
Password string `json:"password"`
}
// CreateUser takes in a create user request and returns the ID of the newly created user.
func (m *Model) CreateUser(req *CreateUserRequest) (int, error) {
if req.Username == "" {
return -1, fmt.Errorf("No username provided")
}
if req.Password == "" {
return -1, fmt.Errorf("No password provided")
}
hash, err := hashPassword(req.Password)
if err != nil {
return -1, err
}
desiredUser := &User{
Username: req.Username,
DisplayName: req.DisplayName,
Password: hash,
}
return m.InsertUser(desiredUser)
}
// UserByUsername retrieves a single username from the store, verifying the passed in userID.
func (m *Model) UserByUsername(username string, userID int) (*UserNoPassword, error) {
user, err := m.SelectUserByUsername(username)
if user == nil {
return nil, wrapNotFound(err)
}
if int(user.UserID) != userID {
return nil, &notFoundError{error: fmt.Errorf("provided userID does not match the retrieved user")}
}
return user.NoPassword(), wrapNotFound(err)
}
// hashPassword hashes a password
func hashPassword(password string) ([]byte, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 11)
return bytes, err
}