86 lines
1.9 KiB
Go
86 lines
1.9 KiB
Go
package routes
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.red-panda.pet/pandaware/house/backend/db"
|
|
"git.red-panda.pet/pandaware/house/backend/middleware"
|
|
"git.red-panda.pet/pandaware/house/backend/router"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
func init() {
|
|
routes["POST"]["/login"] = new(Login)
|
|
}
|
|
|
|
type loginBody struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
type loginResponse struct {
|
|
User db.GetUserRow `json:"user"`
|
|
}
|
|
|
|
type Login struct{}
|
|
|
|
// ValidateBody implements router.ValidatedBodyRoute.
|
|
func (l *Login) ValidateBody(ctx *router.Context) error {
|
|
return middleware.ParseJSONBody[loginBody](ctx)
|
|
}
|
|
|
|
// Handle implements router.Route.
|
|
func (l *Login) Handle(ctx *router.Context) error {
|
|
body := middleware.JSONBody[loginBody](l, ctx)
|
|
|
|
user, err := ctx.Query.GetUserPassword(ctx, body.Username)
|
|
if err != nil {
|
|
return ctx.Error(err, http.StatusBadRequest, "Invalid credentials")
|
|
}
|
|
|
|
err = bcrypt.CompareHashAndPassword(user.Password, []byte(body.Password))
|
|
if err != nil {
|
|
return ctx.Error(err, http.StatusBadRequest, "Invalid credentials")
|
|
}
|
|
|
|
tokenBs := make([]byte, 32)
|
|
_, err = rand.Read(tokenBs)
|
|
if err != nil {
|
|
return ctx.GenericError(err, http.StatusInternalServerError)
|
|
}
|
|
|
|
encodedToken := base64.StdEncoding.EncodeToString(tokenBs)
|
|
hashedToken := sha256.Sum256(tokenBs)
|
|
|
|
_, err = ctx.Query.CreateSession(ctx, db.CreateSessionParams{
|
|
Key: hashedToken[:],
|
|
UserID: user.ID,
|
|
CreatedAt: time.Now().Unix(),
|
|
})
|
|
|
|
if err != nil {
|
|
return ctx.GenericError(err, http.StatusInternalServerError)
|
|
}
|
|
|
|
loggedInUser, err := ctx.Query.GetUser(ctx, user.ID)
|
|
if err != nil {
|
|
return ctx.GenericError(err, http.StatusInternalServerError)
|
|
}
|
|
|
|
ctx.SetCookie(&http.Cookie{
|
|
Name: "session",
|
|
Value: encodedToken,
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
})
|
|
|
|
return ctx.JSON(200, loginResponse{
|
|
User: loggedInUser,
|
|
})
|
|
}
|
|
|
|
var _ router.ValidatedBodyRoute = new(Login)
|