Files
uPortal/internal/auth/service.go
T
2026-10-15 23:25:46 +03:00

114 lines
2.4 KiB
Go

package auth
import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"fmt"
"net"
"net/http"
"strings"
"golang.org/x/crypto/bcrypt"
)
const (
CsrfLength = 32
SessionLength = 32
)
func GenerateToken(length int) (string, error) {
b := make([]byte, length)
_, err := rand.Read(b)
if err != nil {
return "", fmt.Errorf("failed to generate random bytes: %w", err)
}
return base64.RawURLEncoding.EncodeToString(b), nil
}
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(bytes), err
}
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
func SetCsrfCookie(w http.ResponseWriter, r *http.Request, cookieName string) (string, error) {
token, err := GenerateToken(CsrfLength)
if err != nil {
return "", fmt.Errorf("error generating csrf token: %w", err)
}
cookie := &http.Cookie{
Name: cookieName,
Value: token,
Path: "/",
HttpOnly: false,
Secure: true,
SameSite: http.SameSiteLaxMode,
}
http.SetCookie(w, cookie)
return token, nil
}
func ValidateCsrf(r *http.Request, cookieName, fieldName string) error {
cookie, err := r.Cookie(cookieName)
if err != nil {
return fmt.Errorf("missing CSRF cookie")
}
cookieToken := cookie.Value
if err := r.ParseForm(); err != nil {
return fmt.Errorf("failed to parse form data")
}
formToken := r.FormValue(fieldName)
if cookieToken == "" || formToken == "" {
return fmt.Errorf("empty CSRF token")
}
if subtle.ConstantTimeCompare([]byte(cookieToken), []byte(formToken)) != 1 {
return fmt.Errorf("mismatch CSRF token")
}
return nil
}
func extractIP(r *http.Request) string {
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
ips := strings.Split(xff, ",")
return strings.TrimSpace(ips[0])
}
if realIP := r.Header.Get("X-Real-IP"); realIP != "" {
return realIP
}
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return r.RemoteAddr
}
return ip
}
func CreateSession(r *http.Request, userID int64) (string, string, string, error) {
token, err := GenerateToken(SessionLength)
if err != nil {
return "", "", "", err
}
userAgent := r.UserAgent()
if userAgent == "" {
userAgent = "Unknown"
}
ipAddress := extractIP(r)
return token, userAgent, ipAddress, nil
}