init push

This commit is contained in:
2026-07-16 22:16:45 +07:00
commit 8b068bdb10
1021 changed files with 332816 additions and 0 deletions

127
internal/auth/session.go Normal file
View File

@@ -0,0 +1,127 @@
package auth
import (
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"time"
"gorm.io/gorm"
)
type UserSession struct {
UserID string `json:"user_id"`
MicrosoftNameID string `json:"microsoft_name_id"`
Email string `json:"email"`
Name string `json:"name"`
LoggedInAt time.Time `json:"logged_in_at"`
ExpiresAt time.Time `json:"expires_at"`
}
type SessionRecord struct {
Token string `gorm:"type:varchar(128);primaryKey;column:token"`
UserID string `gorm:"type:varchar(191);index;not null;column:user_id"`
MicrosoftNameID string `gorm:"type:varchar(255);index;not null;column:microsoft_name_id"`
Email string `gorm:"type:varchar(191);index;not null;column:email"`
Name string `gorm:"type:varchar(191);not null;column:name"`
LoggedInAt time.Time `gorm:"not null;column:logged_in_at"`
ExpiresAt time.Time `gorm:"index;not null;column:expires_at"`
CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"`
}
func (SessionRecord) TableName() string { return "saml_sessions" }
var sessionDB *gorm.DB
func InitSessionStoreDB(db *gorm.DB) error {
if db == nil {
return fmt.Errorf("database is required")
}
if err := db.AutoMigrate(&SessionRecord{}); err != nil {
return fmt.Errorf("auto migrate saml_sessions: %w", err)
}
sessionDB = db
return nil
}
func CreateSession(session UserSession) (string, error) {
if sessionDB == nil {
return "", fmt.Errorf("session store is not initialized")
}
token, err := generateToken()
if err != nil {
return "", err
}
if session.LoggedInAt.IsZero() {
session.LoggedInAt = time.Now().UTC()
}
if session.ExpiresAt.IsZero() {
session.ExpiresAt = session.LoggedInAt.Add(8 * time.Hour)
}
record := SessionRecord{
Token: token,
UserID: session.UserID,
MicrosoftNameID: session.MicrosoftNameID,
Email: session.Email,
Name: session.Name,
LoggedInAt: session.LoggedInAt,
ExpiresAt: session.ExpiresAt,
}
if err := sessionDB.Create(&record).Error; err != nil {
return "", fmt.Errorf("create session: %w", err)
}
return token, nil
}
func GetSession(token string) (*UserSession, error) {
if sessionDB == nil {
return nil, fmt.Errorf("session store is not initialized")
}
var record SessionRecord
err := sessionDB.Where("token = ?", token).First(&record).Error
if err != nil {
return nil, err
}
now := time.Now().UTC()
if !record.ExpiresAt.After(now) {
_ = sessionDB.Delete(&SessionRecord{}, "token = ?", token).Error
return nil, gorm.ErrRecordNotFound
}
return &UserSession{
UserID: record.UserID,
MicrosoftNameID: record.MicrosoftNameID,
Email: record.Email,
Name: record.Name,
LoggedInAt: record.LoggedInAt,
ExpiresAt: record.ExpiresAt,
}, nil
}
func DeleteSession(token string) error {
if sessionDB == nil {
return fmt.Errorf("session store is not initialized")
}
return sessionDB.Delete(&SessionRecord{}, "token = ?", token).Error
}
func DeleteSessionByNameID(nameID string) error {
if sessionDB == nil {
return fmt.Errorf("session store is not initialized")
}
return sessionDB.Delete(&SessionRecord{}, "microsoft_name_id = ?", nameID).Error
}
func generateToken() (string, error) {
b := make([]byte, 32)
if _, err := rand.Read(b); err != nil {
return "", fmt.Errorf("generate token: %w", err)
}
token := hex.EncodeToString(b)
if token == "" {
return "", errors.New("empty token")
}
return token, nil
}