move files around, make sure cookies work, and add logout

This commit is contained in:
grumbulon 2022-12-30 23:15:09 -05:00
parent c7893eb38e
commit f469d20e06
4 changed files with 140 additions and 90 deletions

View file

@ -2,10 +2,8 @@ package api
import (
"context"
"encoding/json"
"fmt"
"log"
"math/rand"
"net/http"
"time"
@ -14,8 +12,6 @@ import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/jwtauth/v5"
"github.com/go-chi/render"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
func SetDBMiddleware(next http.Handler) http.Handler {
@ -47,10 +43,12 @@ func Api() http.Handler {
})
// Open routes
api.Group(func(api chi.Router) {
api.Use(SetDBMiddleware)
api.With(SetDBMiddleware).Post("/create", NewUser)
api.With(SetDBMiddleware).Post("/login", Login)
api.Post("/logout", Logout)
})
return api
@ -72,92 +70,6 @@ func Ingest(w http.ResponseWriter, r *http.Request) {
// todo -- add functions to apply to master zonefile if above check is OK
}
func NewUser(w http.ResponseWriter, r *http.Request) {
db, ok := r.Context().Value("DB").(*gorm.DB)
if !ok {
http.Error(w, "internal server error", http.StatusInternalServerError)
}
var result internal.User
r.ParseForm()
username := r.Form.Get("username")
if username == "" {
username = autoUname()
}
password := r.Form.Get("password")
if password == "" {
http.Error(w, "No password entered", http.StatusInternalServerError)
}
db.Where("username = ?", username).First(&result)
if result.Username != "" {
http.Error(w, "User already exists", http.StatusInternalServerError)
return
}
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
db.Create(&internal.User{Username: username, HashedPassword: string(hashedPassword)})
data := internal.Response{
Username: username,
HTTPResponse: http.StatusCreated,
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(data)
}
func Login(w http.ResponseWriter, r *http.Request) {
var result internal.User
r.ParseForm()
username := r.Form.Get("username")
if username == "" {
username = autoUname()
}
password := r.Form.Get("password")
if password == "" {
http.Error(w, "No password provided", http.StatusInternalServerError) // this should prob be handled by the frontend
}
db, ok := r.Context().Value("DB").(*gorm.DB)
if !ok {
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
db.Model(internal.User{Username: username}).First(&result)
err := bcrypt.CompareHashAndPassword([]byte(result.HashedPassword), []byte(password))
if err != nil {
basicAuthFailed(w, "user")
return
}
w.WriteHeader(http.StatusAccepted)
token := makeToken(username)
http.SetCookie(w, &http.Cookie{
HttpOnly: true,
Expires: time.Now().Add(7 * 24 * time.Hour),
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,
})
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func autoUname() string {
rand.Seed(time.Now().UnixNano())
return fmt.Sprintf("user%d", rand.Intn(99999-00000))
}
func AuthTest(w http.ResponseWriter, r *http.Request) {
_, claims, _ := jwtauth.FromContext(r.Context())
w.Write([]byte(fmt.Sprintf("protected area. hi %v", claims["user_id"])))

78
internal/api/auth.go Normal file
View file

@ -0,0 +1,78 @@
package api
import (
"encoding/json"
"net/http"
"time"
"git.freecumextremist.com/grumbulon/pomme/internal"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
func Login(w http.ResponseWriter, r *http.Request) {
var result internal.User
r.ParseForm()
username := r.Form.Get("username")
if username == "" {
username = autoUname()
}
password := r.Form.Get("password")
if password == "" {
http.Error(w, "No password provided", http.StatusInternalServerError) // this should prob be handled by the frontend
}
db, ok := r.Context().Value("DB").(*gorm.DB)
if !ok {
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
db.Model(internal.User{Username: username}).First(&result)
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(7 * 24 * time.Hour),
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")
json.NewEncoder(w).Encode(
internal.Response{
Message: "Successfully logged in",
HTTPResponse: 200,
Username: token,
})
http.Redirect(w, r, "/", http.StatusSeeOther)
}
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")
json.NewEncoder(w).Encode(
internal.Response{
Message: "Successfully logged out",
HTTPResponse: 200,
})
http.Redirect(w, r, "/", http.StatusSeeOther)
}

59
internal/api/users.go Normal file
View file

@ -0,0 +1,59 @@
package api
import (
"encoding/json"
"fmt"
"math/rand"
"net/http"
"time"
"git.freecumextremist.com/grumbulon/pomme/internal"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
func NewUser(w http.ResponseWriter, r *http.Request) {
db, ok := r.Context().Value("DB").(*gorm.DB)
if !ok {
http.Error(w, "internal server error", http.StatusInternalServerError)
}
var result internal.User
r.ParseForm()
username := r.Form.Get("username")
if username == "" {
username = autoUname()
}
password := r.Form.Get("password")
if password == "" {
http.Error(w, "No password entered", http.StatusInternalServerError)
}
db.Where("username = ?", username).First(&result)
if result.Username != "" {
http.Error(w, "User already exists", http.StatusInternalServerError)
return
}
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
db.Create(&internal.User{Username: username, HashedPassword: string(hashedPassword)})
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(
internal.Response{
Username: username,
HTTPResponse: http.StatusCreated,
})
}
func autoUname() string {
rand.Seed(time.Now().UnixNano())
return fmt.Sprintf("user%d", rand.Intn(99999-00000))
}

View file

@ -39,6 +39,7 @@ type User struct {
type Response struct {
Username string `json:"username"`
Message string `json:"message"`
HTTPResponse int `json:"status"`
}