feat: initpage com sync Go + auth + frontend em web/
This commit is contained in:
121
internal/handlers/auth.go
Normal file
121
internal/handlers/auth.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/alexedwards/scs/v2"
|
||||
|
||||
"github.com/weltonmoura/initpage/internal/auth"
|
||||
"github.com/weltonmoura/initpage/internal/config"
|
||||
)
|
||||
|
||||
type Auth struct {
|
||||
DB *sql.DB
|
||||
SM *scs.SessionManager
|
||||
Cfg *config.Config
|
||||
}
|
||||
|
||||
type authReq struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Honeypot string `json:"website"`
|
||||
Token string `json:"cf_turnstile_response"`
|
||||
}
|
||||
|
||||
func (h *Auth) Register(w http.ResponseWriter, r *http.Request) {
|
||||
var req authReq
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(`{"error":"dados inválidos"}`))
|
||||
return
|
||||
}
|
||||
if req.Honeypot != "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(`{"error":"rejeitado"}`))
|
||||
return
|
||||
}
|
||||
email := strings.ToLower(strings.TrimSpace(req.Email))
|
||||
if !strings.Contains(email, "@") || len(req.Password) < 6 {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(`{"error":"email ou senha inválidos"}`))
|
||||
return
|
||||
}
|
||||
// Turnstile opcional
|
||||
if h.Cfg.TurnstileSecret != "" && req.Token != "" {
|
||||
// validação simples - implementar se necessário
|
||||
}
|
||||
|
||||
hash, err := auth.HashPasswordSafe(req.Password)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(`{"error":"erro ao criar conta"}`))
|
||||
return
|
||||
}
|
||||
id := randHex(16)
|
||||
_, err = h.DB.Exec(`INSERT INTO users(id,email,password_hash,created_at) VALUES(?,?,?,?)`, id, email, hash, time.Now())
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(`{"error":"email já cadastrado ou inválido"}`))
|
||||
return
|
||||
}
|
||||
h.SM.Put(r.Context(), "user_id", id)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte(`{"ok":true}`))
|
||||
}
|
||||
|
||||
func (h *Auth) Login(w http.ResponseWriter, r *http.Request) {
|
||||
var req authReq
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(`{"error":"dados inválidos"}`))
|
||||
return
|
||||
}
|
||||
email := strings.ToLower(strings.TrimSpace(req.Email))
|
||||
var id, ph string
|
||||
err := h.DB.QueryRow(`SELECT id,password_hash FROM users WHERE email=?`, email).Scan(&id, &ph)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(`{"error":"email ou senha inválidos"}`))
|
||||
return
|
||||
}
|
||||
if !auth.VerifyPassword(ph, req.Password) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(`{"error":"email ou senha inválidos"}`))
|
||||
return
|
||||
}
|
||||
_, _ = h.DB.Exec(`UPDATE users SET last_login_at=? WHERE id=?`, time.Now(), id)
|
||||
h.SM.Put(r.Context(), "user_id", id)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte(`{"ok":true}`))
|
||||
}
|
||||
|
||||
func (h *Auth) Logout(w http.ResponseWriter, r *http.Request) {
|
||||
h.SM.Destroy(r.Context())
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte(`{"ok":true}`))
|
||||
}
|
||||
|
||||
func (h *Auth) Me(w http.ResponseWriter, r *http.Request) {
|
||||
if !h.SM.Exists(r.Context(), "user_id") {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(`{"logged":false}`))
|
||||
return
|
||||
}
|
||||
uid := h.SM.Get(r.Context(), "user_id").(string)
|
||||
var email string
|
||||
_ = h.DB.QueryRow(`SELECT email FROM users WHERE id=?`, uid).Scan(&email)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]any{"logged": true, "email": email})
|
||||
}
|
||||
|
||||
func randHex(n int) string {
|
||||
b := make([]byte, n)
|
||||
rand.Read(b)
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
Reference in New Issue
Block a user