File size: 3,596 Bytes
fe24641
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
from typing import Optional, Dict, Any
from datetime import datetime, timedelta
import secrets
import json
from pathlib import Path

class AuthManager:
    """Manages authentication for HuggingFace Spaces OAuth"""
    
    def __init__(self):
        # OAuth scopes for HuggingFace Spaces
        self.oauth_scopes = [
            "read-repos",
            "write-repos"
        ]
        
        # Session management
        self.sessions = {}
        self.session_timeout = timedelta(hours=8)
    
    def get_oauth_config(self) -> Dict[str, Any]:
        """Get OAuth configuration for HuggingFace Spaces"""
        return {
            "provider": "huggingface",
            "scopes": self.oauth_scopes,
            "expiration_minutes": 480,  # 8 hours
            "allow_anonymous": False
        }
    
    def validate_session(self, session_token: str) -> Optional[Dict[str, Any]]:
        """Validate a session token"""
        if session_token in self.sessions:
            session = self.sessions[session_token]
            if datetime.now() < session['expires']:
                # Update last access
                session['last_access'] = datetime.now()
                return session['user_data']
        return None
    
    def create_session(self, oauth_profile: Dict[str, Any]) -> str:
        """Create a new session for authenticated user"""
        session_token = secrets.token_urlsafe(32)
        
        self.sessions[session_token] = {
            'user_data': {
                'username': oauth_profile.get('preferred_username', oauth_profile.get('username')),
                'name': oauth_profile.get('name', 'Anonymous'),
                'avatar_url': oauth_profile.get('picture', oauth_profile.get('avatar_url')),
                'auth_time': datetime.now().isoformat()
            },
            'created': datetime.now(),
            'expires': datetime.now() + self.session_timeout,
            'last_access': datetime.now()
        }
        
        return session_token
    
    def cleanup_expired_sessions(self):
        """Remove expired sessions"""
        current_time = datetime.now()
        expired_tokens = [
            token for token, session in self.sessions.items()
            if current_time > session['expires']
        ]
        
        for token in expired_tokens:
            del self.sessions[token]
    
    def get_user_permissions(self, username: str) -> Dict[str, bool]:
        """Get user permissions"""
        # In HuggingFace Spaces, all authenticated users have same permissions
        return {
            'can_create_monster': True,
            'can_train': True,
            'can_evolve': True,
            'can_battle': True,
            'can_export': True,
            'max_monsters': 10,
            'max_daily_generations': 50
        }
    
    def log_user_action(self, username: str, action: str, details: Dict = None):
        """Log user actions for analytics"""
        # This would typically write to a database or analytics service
        # For HF Spaces, we'll just print for now
        log_entry = {
            'timestamp': datetime.now().isoformat(),
            'username': username,
            'action': action,
            'details': details or {}
        }
        print(f"User Action: {json.dumps(log_entry)}")
    
    def format_oauth_button_config(self) -> Dict[str, Any]:
        """Format configuration for Gradio LoginButton"""
        return {
            "value": "Connect to Digital World",
            "size": "lg",
            "icon": "🔐",
            "variant": "primary"
        }