Refactor "Token" to "Character" which is what it actually is
This commit is contained in:
22
db.go
22
db.go
@@ -12,8 +12,8 @@ import (
|
|||||||
type DB interface {
|
type DB interface {
|
||||||
DB() *gorm.DB
|
DB() *gorm.DB
|
||||||
Raw(sql string, args ...any) *gorm.DB
|
Raw(sql string, args ...any) *gorm.DB
|
||||||
GetTokenForCharacter(characterName string) (*Token, error)
|
GetCharacterByName(characterName string) (*Character, error)
|
||||||
SaveTokenForCharacter(token *Token) error
|
SaveCharacter(character *Character) error
|
||||||
AutoMigrate(dst ...interface{}) error
|
AutoMigrate(dst ...interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,25 +55,25 @@ func (db *DBWrapper) DB() *gorm.DB {
|
|||||||
return db.db
|
return db.db
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DBWrapper) GetTokenForCharacter(characterName string) (*Token, error) {
|
func (db *DBWrapper) GetCharacterByName(characterName string) (*Character, error) {
|
||||||
logger.Debug("Fetching token for character %s from database", characterName)
|
logger.Debug("Fetching token for character %s from database", characterName)
|
||||||
var token Token
|
var char Character
|
||||||
err := db.db.Where("character_name = ?", characterName).First(&token).Error
|
err := db.db.Where("character_name = ?", characterName).First(&char).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Debug("No token found for character %s: %v", characterName, err)
|
logger.Debug("No token found for character %s: %v", characterName, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
logger.Debug("Token found for character %s, expires at %v", characterName, token.ExpiresAt)
|
logger.Debug("Token found for character %s, expires at %v", characterName, char.ExpiresAt)
|
||||||
return &token, nil
|
return &char, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DBWrapper) SaveTokenForCharacter(token *Token) error {
|
func (db *DBWrapper) SaveCharacter(character *Character) error {
|
||||||
logger.Debug("Saving token for character %s to database", token.CharacterName)
|
logger.Debug("Saving token for character %s to database", character.CharacterName)
|
||||||
err := db.db.Save(token).Error
|
err := db.db.Save(character).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Debug("Token saved successfully for character %s", token.CharacterName)
|
logger.Debug("Token saved successfully for character %s", character.CharacterName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
58
esi_sso.go
58
esi_sso.go
@@ -28,7 +28,7 @@ const (
|
|||||||
issuerTokenURL = "https://login.eveonline.com/v2/oauth/token"
|
issuerTokenURL = "https://login.eveonline.com/v2/oauth/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Token struct {
|
type Character struct {
|
||||||
ID uint `gorm:"primaryKey"`
|
ID uint `gorm:"primaryKey"`
|
||||||
CharacterName string `gorm:"uniqueIndex"`
|
CharacterName string `gorm:"uniqueIndex"`
|
||||||
AccessToken string
|
AccessToken string
|
||||||
@@ -88,7 +88,7 @@ func (s *SSO) SetRouter(r *router.Router) {
|
|||||||
|
|
||||||
func (s *SSO) initDB() error {
|
func (s *SSO) initDB() error {
|
||||||
logger.Debug("Initializing SSO database schema")
|
logger.Debug("Initializing SSO database schema")
|
||||||
err := s.db.AutoMigrate(&Token{})
|
err := s.db.AutoMigrate(&Character{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to migrate Token table %v", err)
|
logger.Error("Failed to migrate Token table %v", err)
|
||||||
return err
|
return err
|
||||||
@@ -100,46 +100,46 @@ func (s *SSO) initDB() error {
|
|||||||
// GetToken returns a valid access token for the given character name
|
// GetToken returns a valid access token for the given character name
|
||||||
// If no token exists, it will start the OAuth flow
|
// If no token exists, it will start the OAuth flow
|
||||||
// If token is expired, it will refresh it automatically
|
// If token is expired, it will refresh it automatically
|
||||||
func (s *SSO) GetToken(ctx context.Context, characterName string) (string, error) {
|
func (s *SSO) GetCharacter(ctx context.Context, characterName string) (Character, error) {
|
||||||
logger.Debug("Getting token for character %s", characterName)
|
logger.Debug("Getting token for character %s", characterName)
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
// Try to get existing token from DB
|
// Try to get existing token from DB
|
||||||
token, err := s.db.GetTokenForCharacter(characterName)
|
char, err := s.db.GetCharacterByName(characterName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
logger.Info("No existing token found for character %s, starting authentication flow", characterName)
|
logger.Info("No existing token found for character %s, starting authentication flow", characterName)
|
||||||
// No token exists, need to authenticate
|
// No token exists, need to authenticate
|
||||||
if err := s.startAuthFlow(ctx, characterName); err != nil {
|
if err := s.startAuthFlow(ctx, characterName); err != nil {
|
||||||
return "", err
|
return Character{}, err
|
||||||
}
|
}
|
||||||
// After authentication, fetch the token from DB
|
// After authentication, fetch the token from DB
|
||||||
token, err = s.db.GetTokenForCharacter(characterName)
|
char, err = s.db.GetCharacterByName(characterName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return Character{}, err
|
||||||
}
|
}
|
||||||
logger.Info("Successfully authenticated character %s", characterName)
|
logger.Info("Successfully authenticated character %s", characterName)
|
||||||
} else {
|
} else {
|
||||||
return "", err
|
return Character{}, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.Debug("Found existing token for character %s, expires at %v", characterName, token.ExpiresAt)
|
logger.Debug("Found existing token for character %s, expires at %v", characterName, char.ExpiresAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if token needs refresh
|
// Check if token needs refresh
|
||||||
if time.Now().After(token.ExpiresAt.Add(-60 * time.Second)) {
|
if time.Now().After(char.ExpiresAt.Add(-12 * time.Hour)) {
|
||||||
logger.Info("Token for character %s is expired or expiring soon, refreshing", characterName)
|
logger.Info("Token for character %s is expired or expiring soon, refreshing", characterName)
|
||||||
if err := s.refreshToken(ctx, token); err != nil {
|
if err := s.refreshToken(ctx, char); err != nil {
|
||||||
logger.Warning("Token refresh failed for character %s, re-authenticating: %v", characterName, err)
|
logger.Warning("Token refresh failed for character %s, re-authenticating: %v", characterName, err)
|
||||||
// Refresh failed, need to re-authenticate
|
// Refresh failed, need to re-authenticate
|
||||||
if err := s.startAuthFlow(ctx, characterName); err != nil {
|
if err := s.startAuthFlow(ctx, characterName); err != nil {
|
||||||
return "", err
|
return Character{}, err
|
||||||
}
|
}
|
||||||
// After re-authentication, fetch the token from DB
|
// After re-authentication, fetch the token from DB
|
||||||
token, err = s.db.GetTokenForCharacter(characterName)
|
char, err = s.db.GetCharacterByName(characterName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return Character{}, err
|
||||||
}
|
}
|
||||||
logger.Info("Successfully re-authenticated character %s", characterName)
|
logger.Info("Successfully re-authenticated character %s", characterName)
|
||||||
} else {
|
} else {
|
||||||
@@ -150,7 +150,7 @@ func (s *SSO) GetToken(ctx context.Context, characterName string) (string, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("Returning valid token for character %s", characterName)
|
logger.Debug("Returning valid token for character %s", characterName)
|
||||||
return token.AccessToken, nil
|
return *char, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSO) startAuthFlow(ctx context.Context, characterName string) error {
|
func (s *SSO) startAuthFlow(ctx context.Context, characterName string) error {
|
||||||
@@ -196,15 +196,15 @@ func (s *SSO) startAuthFlow(ctx context.Context, characterName string) error {
|
|||||||
|
|
||||||
logger.Debug("Received valid callback, exchanging code for token")
|
logger.Debug("Received valid callback, exchanging code for token")
|
||||||
// Exchange code for token
|
// Exchange code for token
|
||||||
token, err := s.exchangeCodeForToken(ctx, code, verifier)
|
char, err := s.exchangeCodeForToken(ctx, code, verifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save token to DB
|
// Save token to DB
|
||||||
token.CharacterName = characterName
|
char.CharacterName = characterName
|
||||||
logger.Debug("Saving token to database for character %s", characterName)
|
logger.Debug("Saving token to database for character %s", characterName)
|
||||||
if err := s.db.SaveTokenForCharacter(token); err != nil {
|
if err := s.db.SaveCharacter(char); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +303,7 @@ func (s *SSO) waitForCallback() (code, state string, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSO) exchangeCodeForToken(ctx context.Context, code, verifier string) (*Token, error) {
|
func (s *SSO) exchangeCodeForToken(ctx context.Context, code, verifier string) (*Character, error) {
|
||||||
logger.Debug("Exchanging authorization code for access token")
|
logger.Debug("Exchanging authorization code for access token")
|
||||||
form := url.Values{}
|
form := url.Values{}
|
||||||
form.Set("grant_type", "authorization_code")
|
form.Set("grant_type", "authorization_code")
|
||||||
@@ -339,7 +339,7 @@ func (s *SSO) exchangeCodeForToken(ctx context.Context, code, verifier string) (
|
|||||||
name, _ := parseTokenCharacter(tr.AccessToken)
|
name, _ := parseTokenCharacter(tr.AccessToken)
|
||||||
logger.Info("Successfully exchanged code for token, character: %s", name)
|
logger.Info("Successfully exchanged code for token, character: %s", name)
|
||||||
|
|
||||||
return &Token{
|
return &Character{
|
||||||
CharacterName: name,
|
CharacterName: name,
|
||||||
AccessToken: tr.AccessToken,
|
AccessToken: tr.AccessToken,
|
||||||
RefreshToken: tr.RefreshToken,
|
RefreshToken: tr.RefreshToken,
|
||||||
@@ -347,11 +347,11 @@ func (s *SSO) exchangeCodeForToken(ctx context.Context, code, verifier string) (
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSO) refreshToken(ctx context.Context, token *Token) error {
|
func (s *SSO) refreshToken(ctx context.Context, char *Character) error {
|
||||||
logger.Debug("Refreshing token for character %s", token.CharacterName)
|
logger.Debug("Refreshing token for character %s", char.CharacterName)
|
||||||
form := url.Values{}
|
form := url.Values{}
|
||||||
form.Set("grant_type", "refresh_token")
|
form.Set("grant_type", "refresh_token")
|
||||||
form.Set("refresh_token", token.RefreshToken)
|
form.Set("refresh_token", char.RefreshToken)
|
||||||
form.Set("client_id", s.clientID)
|
form.Set("client_id", s.clientID)
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, issuerTokenURL, strings.NewReader(form.Encode()))
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, issuerTokenURL, strings.NewReader(form.Encode()))
|
||||||
@@ -379,20 +379,20 @@ func (s *SSO) refreshToken(ctx context.Context, token *Token) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update token
|
// Update token
|
||||||
token.AccessToken = tr.AccessToken
|
char.AccessToken = tr.AccessToken
|
||||||
if tr.RefreshToken != "" {
|
if tr.RefreshToken != "" {
|
||||||
token.RefreshToken = tr.RefreshToken
|
char.RefreshToken = tr.RefreshToken
|
||||||
}
|
}
|
||||||
if tr.ExpiresIn > 0 {
|
if tr.ExpiresIn > 0 {
|
||||||
token.ExpiresAt = time.Now().Add(time.Duration(tr.ExpiresIn-30) * time.Second)
|
char.ExpiresAt = time.Now().Add(time.Duration(tr.ExpiresIn-30) * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("Saving refreshed token to database for character %s", token.CharacterName)
|
logger.Debug("Saving refreshed token to database for character %s", char.CharacterName)
|
||||||
if err := s.db.SaveTokenForCharacter(token); err != nil {
|
if err := s.db.SaveCharacter(char); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("Token refreshed successfully for character %s", token.CharacterName)
|
logger.Info("Token refreshed successfully for character %s", char.CharacterName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user