pomme/internal/api/auth.go

137 lines
2.9 KiB
Go

package api
import (
"encoding/json"
"net/http"
"time"
"git.freecumextremist.com/grumbulon/pomme/internal"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
// Login checks user credentials and creates a jwt session.
func Login(w http.ResponseWriter, r *http.Request) {
var result internal.User
if _, err := r.Cookie("jwt"); err == nil {
http.Error(w, "Logged in", http.StatusCreated)
return
}
w.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(
internal.Response{
Message: "Successfully logged in",
HTTPResponse: 200,
})
if err != nil {
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
err = r.ParseForm()
if err != nil {
http.Error(w, "Unable to parse request", http.StatusInternalServerError)
return
}
username := r.Form.Get("username")
password := r.Form.Get("password")
if username == "" {
http.Error(w, "No username provided", http.StatusInternalServerError) // this should prob be handled by the frontend
return
}
if password == "" {
http.Error(w, "No password provided", http.StatusInternalServerError) // this should prob be handled by the frontend
return
}
db, ok := r.Context().Value(keyPrincipalContextID).(*gorm.DB)
if !ok {
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
db.Where("username = ?", username).First(&result)
if result.Username == "" {
http.Error(w, "login failed", http.StatusUnauthorized)
return
}
err = bcrypt.CompareHashAndPassword([]byte(result.HashedPassword), []byte(password))
if err != nil {
basicAuthFailed(w, "user")
return
}
token := makeToken(username)
http.SetCookie(w, &http.Cookie{
HttpOnly: true,
Expires: time.Now().Add(1 * time.Hour),
MaxAge: 3600,
SameSite: http.SameSiteLaxMode,
// Uncomment below for HTTPS:
// Secure: true,
Name: "jwt", // Must be named "jwt" or else the token cannot be searched for by jwtauth.Verifier.
Value: token,
})
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(
internal.Response{
Message: "Successfully logged in",
HTTPResponse: 200,
})
if err != nil {
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/", http.StatusSeeOther)
}
// Logout destroys a users JWT cookie.
func Logout(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &http.Cookie{
HttpOnly: true,
MaxAge: -1, // Delete the cookie.
SameSite: http.SameSiteLaxMode,
// Secure: true,
Name: "jwt",
Value: "",
})
w.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(
internal.Response{
Message: "Successfully logged out",
HTTPResponse: 200,
})
if err != nil {
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/", http.StatusSeeOther)
}