lots of stuff, don't truly remember

This commit is contained in:
Blake Ridgway
2026-05-17 20:39:47 -05:00
parent 178ffb3425
commit dc4fe558b7
35 changed files with 3501 additions and 112 deletions

View File

@@ -2,8 +2,12 @@ package auth
import (
"encoding/json"
"io"
"log"
"net/http"
"net/url"
"os"
"strings"
"rideaware/internal/config"
"rideaware/internal/user"
@@ -20,11 +24,12 @@ func NewHandler() *Handler {
}
type SignupRequest struct {
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
TurnstileToken string `json:"turnstile_token"`
}
type LoginRequest struct {
@@ -39,6 +44,7 @@ type TokenResponse struct {
UserID uint `json:"user_id"`
Username string `json:"username"`
Email string `json:"email"`
Role string `json:"role"`
}
func (h *Handler) Signup(w http.ResponseWriter, r *http.Request) {
@@ -55,6 +61,25 @@ func (h *Handler) Signup(w http.ResponseWriter, r *http.Request) {
log.Printf("📝 Signup attempt for user: %s (email: %s)", req.Username, req.Email)
// Verify Turnstile CAPTCHA
turnstileSecret := os.Getenv("TURNSTILE_SECRET_KEY")
if turnstileSecret != "" {
if req.TurnstileToken == "" {
log.Printf("❌ Signup rejected: missing Turnstile token for %s", req.Username)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{"error": "Please complete the verification check"})
return
}
if !verifyTurnstile(turnstileSecret, req.TurnstileToken, r.RemoteAddr) {
log.Printf("❌ Signup rejected: Turnstile verification failed for %s", req.Username)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{"error": "CAPTCHA verification failed. Please try again."})
return
}
}
newUser, err := h.userService.CreateUser(req.Username, req.Password, req.Email, req.FirstName, req.LastName)
if err != nil {
log.Printf("❌ Signup error: %v", err)
@@ -66,18 +91,19 @@ func (h *Handler) Signup(w http.ResponseWriter, r *http.Request) {
log.Printf("✅ User created: %s (ID: %d)", newUser.Username, newUser.ID)
accessToken, _ := config.GenerateAccessToken(newUser.ID, newUser.Email, newUser.Username)
refreshToken, _ := config.GenerateRefreshToken(newUser.ID, newUser.Email, newUser.Username)
accessToken, _ := config.GenerateAccessToken(newUser.ID, newUser.Email, newUser.Username, newUser.Role)
refreshToken, _ := config.GenerateRefreshToken(newUser.ID, newUser.Email, newUser.Username, newUser.Role)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(TokenResponse{
AccessToken: accessToken,
RefreshToken: refreshToken,
ExpiresIn: 900,
ExpiresIn: 86400, // 24 hours in seconds
UserID: newUser.ID,
Username: newUser.Username,
Email: newUser.Email,
Role: newUser.Role,
})
}
@@ -106,17 +132,18 @@ func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
log.Printf("✅ Login successful for user: %s (ID: %d)", user.Username, user.ID)
accessToken, _ := config.GenerateAccessToken(user.ID, user.Email, user.Username)
refreshToken, _ := config.GenerateRefreshToken(user.ID, user.Email, user.Username)
accessToken, _ := config.GenerateAccessToken(user.ID, user.Email, user.Username, user.Role)
refreshToken, _ := config.GenerateRefreshToken(user.ID, user.Email, user.Username, user.Role)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{
AccessToken: accessToken,
RefreshToken: refreshToken,
ExpiresIn: 900,
ExpiresIn: 86400, // 24 hours in seconds
UserID: user.ID,
Username: user.Username,
Email: user.Email,
Role: user.Role,
})
}
@@ -149,12 +176,12 @@ func (h *Handler) RefreshToken(w http.ResponseWriter, r *http.Request) {
log.Printf("✅ Refresh token valid for user ID: %d", claims.UserID)
// Generate new access token
newAccessToken, _ := config.GenerateAccessToken(claims.UserID, claims.Email, claims.Username)
newAccessToken, _ := config.GenerateAccessToken(claims.UserID, claims.Email, claims.Username, claims.Role)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"access_token": newAccessToken,
"expires_in": 900,
"expires_in": 86400, // 24 hours in seconds
})
}
@@ -228,4 +255,39 @@ func (h *Handler) Logout(w http.ResponseWriter, r *http.Request) {
log.Println("👋 Logout request received")
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"message": "Logout successful"})
}
}
func verifyTurnstile(secret, token, remoteIP string) bool {
// Strip port from RemoteAddr if present
if idx := strings.LastIndex(remoteIP, ":"); idx != -1 {
remoteIP = remoteIP[:idx]
}
resp, err := http.PostForm("https://challenges.cloudflare.com/turnstile/v0/siteverify",
url.Values{
"secret": {secret},
"response": {token},
"remoteip": {remoteIP},
})
if err != nil {
log.Printf("❌ Turnstile verification request failed: %v", err)
return false
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Printf("❌ Turnstile verification read failed: %v", err)
return false
}
var result struct {
Success bool `json:"success"`
}
if err := json.Unmarshal(body, &result); err != nil {
log.Printf("❌ Turnstile verification parse failed: %v", err)
return false
}
return result.Success
}