package admin import ( "crypto/rand" "crypto/sha256" "encoding/base64" "encoding/hex" "errors" "fmt" "net/http" "time" "github.com/gin-gonic/gin" "golang.org/x/crypto/bcrypt" ) const SessionCookieName = "osaet_admin_session" var ErrInvalidCredentials = errors.New("invalid username or password") type contextKey string const userContextKey contextKey = "adminUser" func HashPassword(password string) (string, error) { if password == "" { return "", errors.New("password is required") } hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return "", fmt.Errorf("hash password: %w", err) } return string(hash), nil } func CheckPassword(hash string, password string) bool { return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil } func NewSessionToken() (string, error) { token := make([]byte, 32) if _, err := rand.Read(token); err != nil { return "", fmt.Errorf("generate session token: %w", err) } return base64.RawURLEncoding.EncodeToString(token), nil } func SessionTokenHash(token string) string { sum := sha256.Sum256([]byte(token)) return hex.EncodeToString(sum[:]) } func SetSessionCookie(c *gin.Context, token string, expiresAt time.Time) { http.SetCookie(c.Writer, &http.Cookie{ Name: SessionCookieName, Value: token, Path: "/", Expires: expiresAt, MaxAge: int(time.Until(expiresAt).Seconds()), HttpOnly: true, SameSite: http.SameSiteLaxMode, }) } func ClearSessionCookie(c *gin.Context) { http.SetCookie(c.Writer, &http.Cookie{ Name: SessionCookieName, Value: "", Path: "/", Expires: time.Unix(0, 0), MaxAge: -1, HttpOnly: true, SameSite: http.SameSiteLaxMode, }) }