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) } // hashPassword hashes a password func hashPassword(password string) ([]byte, error) { bytes, err := bcrypt.GenerateFromPassword([]byte(password), 11) return bytes, err }