This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/consent-service/internal/session/session_middleware.go
BreakPilot Dev 19855efacc
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
feat: BreakPilot PWA - Full codebase (clean push without large binaries)
All services: admin-v2, studio-v2, website, ai-compliance-sdk,
consent-service, klausur-service, voice-service, and infrastructure.
Large PDFs and compiled binaries excluded via .gitignore.
2026-02-11 13:25:58 +01:00

197 lines
4.5 KiB
Go

package session
import (
"net/http"
"os"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
)
// SessionMiddleware extracts session from request and adds to context
func SessionMiddleware(pgPool *pgxpool.Pool) gin.HandlerFunc {
store := GetSessionStore(pgPool)
return func(c *gin.Context) {
sessionID := extractSessionID(c)
if sessionID != "" {
session, err := store.GetSession(c.Request.Context(), sessionID)
if err == nil && session != nil {
// Add session to context
c.Set("session", session)
c.Set("session_id", session.SessionID)
c.Set("user_id", session.UserID)
c.Set("email", session.Email)
c.Set("user_type", string(session.UserType))
c.Set("roles", session.Roles)
c.Set("permissions", session.Permissions)
if session.TenantID != nil {
c.Set("tenant_id", *session.TenantID)
}
}
}
c.Next()
}
}
// extractSessionID extracts session ID from request
func extractSessionID(c *gin.Context) string {
// Try Authorization header first
authHeader := c.GetHeader("Authorization")
if strings.HasPrefix(authHeader, "Bearer ") {
return strings.TrimPrefix(authHeader, "Bearer ")
}
// Try X-Session-ID header
if sessionID := c.GetHeader("X-Session-ID"); sessionID != "" {
return sessionID
}
// Try cookie
if cookie, err := c.Cookie("session_id"); err == nil {
return cookie
}
return ""
}
// RequireSession requires a valid session
func RequireSession() gin.HandlerFunc {
return func(c *gin.Context) {
session := GetSession(c)
if session == nil {
// Check development bypass
if os.Getenv("ENVIRONMENT") == "development" {
// Set demo session
demoSession := getDemoSession()
c.Set("session", demoSession)
c.Set("session_id", demoSession.SessionID)
c.Set("user_id", demoSession.UserID)
c.Set("email", demoSession.Email)
c.Set("user_type", string(demoSession.UserType))
c.Set("roles", demoSession.Roles)
c.Set("permissions", demoSession.Permissions)
c.Next()
return
}
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"error": "unauthorized",
"message": "Authentication required",
})
return
}
c.Next()
}
}
// GetSession retrieves session from context
func GetSession(c *gin.Context) *Session {
if session, exists := c.Get("session"); exists {
if s, ok := session.(*Session); ok {
return s
}
}
return nil
}
// GetSessionUserID retrieves user ID from session context
func GetSessionUserID(c *gin.Context) (uuid.UUID, error) {
userIDStr, exists := c.Get("user_id")
if !exists {
return uuid.Nil, nil
}
return uuid.Parse(userIDStr.(string))
}
// GetSessionEmail retrieves email from session context
func GetSessionEmail(c *gin.Context) string {
email, exists := c.Get("email")
if !exists {
return ""
}
return email.(string)
}
// GetSessionUserType retrieves user type from session context
func GetSessionUserType(c *gin.Context) UserType {
userType, exists := c.Get("user_type")
if !exists {
return UserTypeCustomer
}
return UserType(userType.(string))
}
// GetSessionRoles retrieves roles from session context
func GetSessionRoles(c *gin.Context) []string {
roles, exists := c.Get("roles")
if !exists {
return nil
}
if r, ok := roles.([]string); ok {
return r
}
return nil
}
// GetSessionPermissions retrieves permissions from session context
func GetSessionPermissions(c *gin.Context) []string {
perms, exists := c.Get("permissions")
if !exists {
return nil
}
if p, ok := perms.([]string); ok {
return p
}
return nil
}
// GetSessionTenantID retrieves tenant ID from session context
func GetSessionTenantID(c *gin.Context) *string {
tenantID, exists := c.Get("tenant_id")
if !exists {
return nil
}
if t, ok := tenantID.(string); ok {
return &t
}
return nil
}
// getDemoSession returns a demo session for development
func getDemoSession() *Session {
tenantID := "a0000000-0000-0000-0000-000000000001"
ip := "127.0.0.1"
ua := "Development"
return &Session{
SessionID: "demo-session-id",
UserID: "10000000-0000-0000-0000-000000000024",
Email: "demo@breakpilot.app",
UserType: UserTypeEmployee,
Roles: []string{
"admin", "schul_admin", "teacher",
},
Permissions: []string{
"grades:read", "grades:write",
"attendance:read", "attendance:write",
"students:read", "students:write",
"reports:generate", "consent:admin",
"own_data:read", "users:manage",
},
TenantID: &tenantID,
IPAddress: &ip,
UserAgent: &ua,
CreatedAt: time.Now().UTC(),
LastActivityAt: time.Now().UTC(),
}
}