76 lines
1.8 KiB
Go
76 lines
1.8 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"database/sql"
|
||
|
"errors"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"time"
|
||
|
|
||
|
"webscaffold/models"
|
||
|
|
||
|
"github.com/gofrs/uuid"
|
||
|
"github.com/volatiletech/sqlboiler/boil"
|
||
|
"github.com/volatiletech/sqlboiler/queries/qm"
|
||
|
)
|
||
|
|
||
|
type apiLoginResponse struct {
|
||
|
SessionKey string
|
||
|
}
|
||
|
|
||
|
func (this *Application) apiLogin(r *http.Request) (*apiLoginResponse, netError) {
|
||
|
|
||
|
ctx := r.Context()
|
||
|
email := r.PostFormValue(`email`)
|
||
|
passwd := r.PostFormValue(`password`)
|
||
|
|
||
|
// find user with matching email
|
||
|
user, err := models.Users(qm.Where(`email = ?`, email), qm.Limit(1)).One(ctx, this.db)
|
||
|
if err != nil {
|
||
|
if errors.Is(err, sql.ErrNoRows) {
|
||
|
return nil, userFacingError{code: 403, e: errors.New(`Invalid authentication`)}
|
||
|
}
|
||
|
|
||
|
return nil, systemError{err}
|
||
|
}
|
||
|
|
||
|
// verify password
|
||
|
ok, err := verifyPassword(int(user.PasswordFormat), user.PasswordHash, passwd)
|
||
|
if err != nil {
|
||
|
return nil, systemError{err}
|
||
|
}
|
||
|
if !ok {
|
||
|
return nil, userFacingError{code: 403, e: errors.New(`Invalid authentication`)}
|
||
|
}
|
||
|
|
||
|
// Successful login
|
||
|
// Maybe upgrade password format?
|
||
|
if int(user.PasswordFormat) != hashFmtPreferred {
|
||
|
if newHash, err := hashPassword(hashFmtPreferred, passwd); err == nil {
|
||
|
user.PasswordFormat = int64(hashFmtPreferred)
|
||
|
user.PasswordHash = newHash
|
||
|
_, err := user.Update(ctx, this.db, boil.Whitelist(models.UserColumns.PasswordFormat, models.UserColumns.PasswordHash))
|
||
|
if err != nil {
|
||
|
// Continue, but log error
|
||
|
log.Printf(`couldn't update stored hash format for user '%s': %s`, email, err.Error())
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Create a session token
|
||
|
sess := models.Session{
|
||
|
ID: uuid.Must(uuid.NewV4()).String(),
|
||
|
Mtime: time.Now().Unix(),
|
||
|
UserID: user.ID,
|
||
|
}
|
||
|
err = sess.Insert(ctx, this.db, boil.Infer())
|
||
|
if err != nil {
|
||
|
return nil, systemError{err}
|
||
|
}
|
||
|
|
||
|
// Successful login
|
||
|
return &apiLoginResponse{SessionKey: sess.ID}, nil
|
||
|
|
||
|
}
|