authix-python-sdk 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
authix/__init__.py ADDED
@@ -0,0 +1,23 @@
1
+ """
2
+ Authix Python SDK
3
+ Official Python SDK for the Authix authentication service
4
+ """
5
+
6
+ __version__ = "1.0.0"
7
+ __author__ = "Authix Team"
8
+ __email__ = "support@authix.com"
9
+
10
+ from .api import AuthixAPI
11
+ from .client import APIClient
12
+ from .handlers import AuthHandler, AppsHandler, LicensesHandler, UsersHandler, SecurityHandler, WebhooksHandler
13
+
14
+ __all__ = [
15
+ "AuthixAPI",
16
+ "APIClient",
17
+ "AuthHandler",
18
+ "AppsHandler",
19
+ "LicensesHandler",
20
+ "UsersHandler",
21
+ "SecurityHandler",
22
+ "WebhooksHandler",
23
+ ]
authix/api.py ADDED
@@ -0,0 +1,81 @@
1
+ """
2
+ Authix API - Main API interface
3
+ Official Python SDK for the Authix authentication service
4
+ """
5
+
6
+ import os
7
+ import asyncio
8
+ from typing import Optional
9
+
10
+ from .client import APIClient
11
+ from .handlers import AuthHandler, AppsHandler, LicensesHandler, UsersHandler, SecurityHandler, WebhooksHandler
12
+
13
+
14
+ class AuthixAPI:
15
+ """
16
+ Main Authix API client that provides access to all Authix services.
17
+
18
+ Example:
19
+ import asyncio
20
+ from authix import AuthixAPI
21
+
22
+ async def main():
23
+ # Initialize with your API key
24
+ api = AuthixAPI(api_key="your_api_key_here")
25
+
26
+ # Register a new user
27
+ result = await api.auth.register(
28
+ username="testuser",
29
+ password="SecurePass123!",
30
+ license_key="AX-XXXX-XXXX-XXXX",
31
+ hwid="device_hash_here",
32
+ app_id="your_app_id",
33
+ app_name="Your App Name"
34
+ )
35
+ print("Registration result:", result)
36
+
37
+ # Login user
38
+ login_result = await api.auth.login(
39
+ username="testuser",
40
+ password="SecurePass123!",
41
+ hwid="device_hash_here",
42
+ app_id="your_app_id",
43
+ app_name="Your App Name"
44
+ )
45
+ print("Login result:", login_result)
46
+
47
+ asyncio.run(main())
48
+ """
49
+
50
+ def __init__(self,
51
+ api_key: Optional[str] = None,
52
+ server_url: Optional[str] = None,
53
+ timeout: int = 30):
54
+ """
55
+ Initialize Authix API client
56
+
57
+ Args:
58
+ api_key: Your Authix API key (can be set via AUTHIX_API_KEY env var)
59
+ server_url: Authix server URL (can be set via AUTHIX_SERVER env var)
60
+ timeout: Request timeout in seconds
61
+ """
62
+ # Get configuration from parameters or environment
63
+ self.api_key = api_key or os.getenv("AUTHIX_API_KEY")
64
+ self.server_url = server_url or os.getenv("AUTHIX_SERVER", "https://getauthix.online")
65
+
66
+ if not self.api_key:
67
+ raise RuntimeError("API key is required. Set it via parameter or AUTHIX_API_KEY environment variable")
68
+
69
+ # Initialize the HTTP client
70
+ self.client = APIClient(server_url=self.server_url, api_key=self.api_key, timeout=timeout)
71
+
72
+ # Initialize handlers
73
+ self.auth = AuthHandler(self.client)
74
+ self.apps = AppsHandler(self.client)
75
+ self.licenses = LicensesHandler(self.client)
76
+ self.users = UsersHandler(self.client)
77
+ self.security = SecurityHandler(self.client)
78
+ self.webhooks = WebhooksHandler(self.client)
79
+
80
+ def __repr__(self):
81
+ return f"AuthixAPI(server_url='{self.server_url}', api_key='...{self.api_key[-8:]}')"
authix/cli.py ADDED
@@ -0,0 +1,252 @@
1
+ """
2
+ Authix CLI
3
+ Command-line interface for Authix operations
4
+ """
5
+
6
+ import argparse
7
+ import asyncio
8
+ import json
9
+ import os
10
+ import sys
11
+ from typing import Dict, Any
12
+
13
+ from .api import AuthixAPI
14
+ from . import __version__
15
+
16
+
17
+ def load_config() -> Dict[str, str]:
18
+ """Load configuration from environment variables"""
19
+ config = {
20
+ 'api_key': os.getenv('AUTHIX_API_KEY'),
21
+ 'server_url': os.getenv('AUTHIX_SERVER', 'https://getauthix.online')
22
+ }
23
+
24
+ if not config['api_key']:
25
+ print("Error: AUTHIX_API_KEY must be set")
26
+ sys.exit(1)
27
+
28
+ return config
29
+
30
+
31
+ async def register_command(args):
32
+ """Register a new user"""
33
+ config = load_config()
34
+ api = AuthixAPI(**config)
35
+
36
+ try:
37
+ result = await api.auth.register(
38
+ username=args.username,
39
+ password=args.password,
40
+ license_key=args.license_key,
41
+ hwid=args.hwid,
42
+ app_id=args.app_id,
43
+ app_name=args.app_name
44
+ )
45
+ print(json.dumps(result, indent=2))
46
+ except Exception as e:
47
+ print(f"Error: {e}")
48
+ sys.exit(1)
49
+ finally:
50
+ await api.client.close()
51
+
52
+
53
+ async def login_command(args):
54
+ """Login user"""
55
+ config = load_config()
56
+ api = AuthixAPI(**config)
57
+
58
+ try:
59
+ result = await api.auth.login(
60
+ username=args.username,
61
+ password=args.password,
62
+ hwid=args.hwid,
63
+ app_id=args.app_id,
64
+ app_name=args.app_name
65
+ )
66
+ print(json.dumps(result, indent=2))
67
+ except Exception as e:
68
+ print(f"Error: {e}")
69
+ sys.exit(1)
70
+ finally:
71
+ await api.client.close()
72
+
73
+
74
+ async def apps_command(args):
75
+ """List applications"""
76
+ config = load_config()
77
+ api = AuthixAPI(**config)
78
+
79
+ try:
80
+ apps = await api.apps.get_apps()
81
+ print(json.dumps(apps, indent=2))
82
+ except Exception as e:
83
+ print(f"Error: {e}")
84
+ sys.exit(1)
85
+ finally:
86
+ await api.client.close()
87
+
88
+
89
+ async def create_app_command(args):
90
+ """Create new application"""
91
+ config = load_config()
92
+ api = AuthixAPI(**config)
93
+
94
+ try:
95
+ data = {'name': args.name}
96
+ if args.description:
97
+ data['description'] = args.description
98
+
99
+ app = await api.apps.create_app(**data)
100
+ print(json.dumps(app, indent=2))
101
+ except Exception as e:
102
+ print(f"Error: {e}")
103
+ sys.exit(1)
104
+ finally:
105
+ await api.client.close()
106
+
107
+
108
+ async def create_license_command(args):
109
+ """Create license"""
110
+ config = load_config()
111
+ api = AuthixAPI(**config)
112
+
113
+ try:
114
+ license_data = await api.licenses.create_license(
115
+ app_id=args.app_id,
116
+ days=args.days,
117
+ max_hwids=args.max_hwids
118
+ )
119
+ print(json.dumps(license_data, indent=2))
120
+ except Exception as e:
121
+ print(f"Error: {e}")
122
+ sys.exit(1)
123
+ finally:
124
+ await api.client.close()
125
+
126
+
127
+ async def ban_hwid_command(args):
128
+ """Ban HWID"""
129
+ config = load_config()
130
+ api = AuthixAPI(**config)
131
+
132
+ try:
133
+ result = await api.security.ban_hwid(args.app_id, args.hwid)
134
+ print(json.dumps(result, indent=2))
135
+ except Exception as e:
136
+ print(f"Error: {e}")
137
+ sys.exit(1)
138
+ finally:
139
+ await api.client.close()
140
+
141
+
142
+ async def create_webhook_command(args):
143
+ """Create webhook"""
144
+ config = load_config()
145
+ api = AuthixAPI(**config)
146
+
147
+ try:
148
+ webhook = await api.webhooks.create_webhook(
149
+ app_id=args.app_id,
150
+ url=args.url,
151
+ events=args.events,
152
+ secret=args.secret
153
+ )
154
+ print(json.dumps(webhook, indent=2))
155
+ except Exception as e:
156
+ print(f"Error: {e}")
157
+ sys.exit(1)
158
+ finally:
159
+ await api.client.close()
160
+
161
+
162
+ async def health_command(args):
163
+ """Check server health"""
164
+ config = load_config()
165
+ api = AuthixAPI(**config)
166
+
167
+ try:
168
+ # Try to get apps as a health check
169
+ await api.apps.get_apps()
170
+ print("✅ Authix server is online and accessible")
171
+ except Exception as e:
172
+ print(f"❌ Server health check failed: {e}")
173
+ sys.exit(1)
174
+ finally:
175
+ await api.client.close()
176
+
177
+
178
+ def main():
179
+ """Main CLI entry point"""
180
+ parser = argparse.ArgumentParser(
181
+ description='Authix CLI - Command-line interface for Authix',
182
+ prog='authix-cli'
183
+ )
184
+ parser.add_argument('--version', action='version', version=f'Authix CLI {__version__}')
185
+
186
+ subparsers = parser.add_subparsers(dest='command', help='Available commands')
187
+
188
+ # Auth commands
189
+ register_parser = subparsers.add_parser('register', help='Register a new user')
190
+ register_parser.add_argument('username', help='Username')
191
+ register_parser.add_argument('password', help='Password')
192
+ register_parser.add_argument('license_key', help='License key')
193
+ register_parser.add_argument('hwid', help='Hardware ID')
194
+ register_parser.add_argument('app_id', help='Application ID')
195
+ register_parser.add_argument('app_name', help='Application name')
196
+ register_parser.set_defaults(func=register_command)
197
+
198
+ login_parser = subparsers.add_parser('login', help='Login user')
199
+ login_parser.add_argument('username', help='Username')
200
+ login_parser.add_argument('password', help='Password')
201
+ login_parser.add_argument('hwid', help='Hardware ID')
202
+ login_parser.add_argument('app_id', help='Application ID')
203
+ login_parser.add_argument('app_name', help='Application name')
204
+ login_parser.set_defaults(func=login_command)
205
+
206
+ # App commands
207
+ apps_parser = subparsers.add_parser('apps', help='List all applications')
208
+ apps_parser.set_defaults(func=apps_command)
209
+
210
+ create_app_parser = subparsers.add_parser('create-app', help='Create a new application')
211
+ create_app_parser.add_argument('name', help='Application name')
212
+ create_app_parser.add_argument('--description', help='Application description')
213
+ create_app_parser.set_defaults(func=create_app_command)
214
+
215
+ # License commands
216
+ license_parser = subparsers.add_parser('create-license', help='Create a new license')
217
+ license_parser.add_argument('app_id', help='Application ID')
218
+ license_parser.add_argument('--days', type=int, default=30, help='License validity in days')
219
+ license_parser.add_argument('--max-hwids', type=int, default=3, help='Maximum allowed hardware IDs')
220
+ license_parser.set_defaults(func=create_license_command)
221
+
222
+ # Security commands
223
+ ban_hwid_parser = subparsers.add_parser('ban-hwid', help='Ban hardware ID')
224
+ ban_hwid_parser.add_argument('app_id', help='Application ID')
225
+ ban_hwid_parser.add_argument('hwid', help='Hardware ID to ban')
226
+ ban_hwid_parser.set_defaults(func=ban_hwid_command)
227
+
228
+ # Webhook commands
229
+ webhook_parser = subparsers.add_parser('create-webhook', help='Create webhook')
230
+ webhook_parser.add_argument('app_id', help='Application ID')
231
+ webhook_parser.add_argument('url', help='Webhook URL')
232
+ webhook_parser.add_argument('--events', nargs='+', required=True, help='Events to subscribe to')
233
+ webhook_parser.add_argument('--secret', help='Webhook secret')
234
+ webhook_parser.set_defaults(func=create_webhook_command)
235
+
236
+ # Health check
237
+ health_parser = subparsers.add_parser('health', help='Check server health')
238
+ health_parser.set_defaults(func=health_command)
239
+
240
+ # Parse arguments
241
+ args = parser.parse_args()
242
+
243
+ if not args.command:
244
+ parser.print_help()
245
+ sys.exit(1)
246
+
247
+ # Execute command
248
+ asyncio.run(args.func(args))
249
+
250
+
251
+ if __name__ == '__main__':
252
+ main()
authix/client.py ADDED
@@ -0,0 +1,110 @@
1
+ """
2
+ Authix HTTP Client
3
+ HTTP client for making requests to Authix API
4
+ """
5
+
6
+ import json
7
+ import asyncio
8
+ import aiohttp
9
+ from typing import Dict, Any, Optional
10
+
11
+
12
+ class APIClient:
13
+ """
14
+ HTTP client for Authix API requests
15
+
16
+ This class handles all HTTP communication with the Authix server.
17
+ """
18
+
19
+ def __init__(self, server_url: str, api_key: str, timeout: int = 30):
20
+ """
21
+ Initialize API client
22
+
23
+ Args:
24
+ server_url: Base URL of Authix server
25
+ api_key: API key for authentication
26
+ timeout: Request timeout in seconds
27
+ """
28
+ self.server_url = server_url.rstrip('/')
29
+ self.api_key = api_key
30
+ self.timeout = aiohttp.ClientTimeout(total=timeout)
31
+ self._session = None
32
+
33
+ async def _get_session(self) -> aiohttp.ClientSession:
34
+ """Get or create aiohttp session"""
35
+ if self._session is None or self._session.closed:
36
+ headers = {
37
+ 'Authorization': f'Bearer {self.api_key}',
38
+ 'Content-Type': 'application/json',
39
+ 'User-Agent': f'Authix-Python-SDK/1.0.0'
40
+ }
41
+ self._session = aiohttp.ClientSession(
42
+ headers=headers,
43
+ timeout=self.timeout
44
+ )
45
+ return self._session
46
+
47
+ async def request(self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
48
+ """
49
+ Make HTTP request to Authix API
50
+
51
+ Args:
52
+ method: HTTP method (GET, POST, PUT, DELETE)
53
+ endpoint: API endpoint
54
+ data: Request data for POST/PUT requests
55
+
56
+ Returns:
57
+ Response data as dictionary
58
+
59
+ Raises:
60
+ RuntimeError: If API request fails
61
+ """
62
+ url = f"{self.server_url}/api/v1{endpoint}"
63
+ session = await self._get_session()
64
+
65
+ try:
66
+ async with session.request(method, url, json=data) as response:
67
+ response_data = await response.json()
68
+
69
+ if response.status >= 400:
70
+ error_msg = response_data.get('error', f'HTTP {response.status}')
71
+ raise RuntimeError(error_msg)
72
+
73
+ return response_data
74
+
75
+ except aiohttp.ClientError as e:
76
+ raise RuntimeError(f"Network error: {str(e)}")
77
+ except json.JSONDecodeError:
78
+ raise RuntimeError("Invalid JSON response from server")
79
+
80
+ async def get(self, endpoint: str) -> Dict[str, Any]:
81
+ """Make GET request"""
82
+ return await self.request('GET', endpoint)
83
+
84
+ async def post(self, endpoint: str, data: Dict[str, Any]) -> Dict[str, Any]:
85
+ """Make POST request"""
86
+ return await self.request('POST', endpoint, data)
87
+
88
+ async def put(self, endpoint: str, data: Dict[str, Any]) -> Dict[str, Any]:
89
+ """Make PUT request"""
90
+ return await self.request('PUT', endpoint, data)
91
+
92
+ async def delete(self, endpoint: str) -> Dict[str, Any]:
93
+ """Make DELETE request"""
94
+ return await self.request('DELETE', endpoint)
95
+
96
+ async def close(self):
97
+ """Close the HTTP session"""
98
+ if self._session and not self._session.closed:
99
+ await self._session.close()
100
+
101
+ def __del__(self):
102
+ """Cleanup when client is destroyed"""
103
+ if self._session and not self._session.closed:
104
+ # Schedule closing for the next event loop iteration
105
+ try:
106
+ loop = asyncio.get_event_loop()
107
+ if loop.is_running():
108
+ loop.create_task(self.close())
109
+ except RuntimeError:
110
+ pass
authix/decorators.py ADDED
@@ -0,0 +1,109 @@
1
+ """
2
+ SecureAuth Decorators
3
+ Authentication and authorization decorators for Flask
4
+ """
5
+
6
+ from flask import g, request, redirect, url_for, abort, jsonify
7
+ from functools import wraps
8
+ from typing import Callable, Any
9
+
10
+
11
+ def require_auth(f: Callable) -> Callable:
12
+ """Decorator to require authentication"""
13
+ @wraps(f)
14
+ def decorated_function(*args, **kwargs):
15
+ if not hasattr(g, 'current_user') or not g.current_user:
16
+ if request.path.startswith('/api/'):
17
+ return jsonify({'success': False, 'error': 'Authentication required'}), 401
18
+ else:
19
+ return redirect(url_for('login'))
20
+ return f(*args, **kwargs)
21
+ return decorated_function
22
+
23
+
24
+ def require_role(*required_roles: str) -> Callable:
25
+ """Decorator to require specific role(s)"""
26
+ def decorator(f: Callable) -> Callable:
27
+ @wraps(f)
28
+ def decorated_function(*args, **kwargs):
29
+ if not hasattr(g, 'current_user') or not g.current_user:
30
+ if request.path.startswith('/api/'):
31
+ return jsonify({'success': False, 'error': 'Authentication required'}), 401
32
+ else:
33
+ return redirect(url_for('login'))
34
+
35
+ user_role = g.current_user.get('role')
36
+ if user_role not in required_roles:
37
+ if request.path.startswith('/api/'):
38
+ return jsonify({'success': False, 'error': 'Insufficient permissions'}), 403
39
+ else:
40
+ abort(403)
41
+
42
+ return f(*args, **kwargs)
43
+ return decorated_function
44
+ return decorator
45
+
46
+
47
+ def require_verification(f: Callable) -> Callable:
48
+ """Decorator to require user verification"""
49
+ @wraps(f)
50
+ def decorated_function(*args, **kwargs):
51
+ if not hasattr(g, 'current_user') or not g.current_user:
52
+ if request.path.startswith('/api/'):
53
+ return jsonify({'success': False, 'error': 'Authentication required'}), 401
54
+ else:
55
+ return redirect(url_for('login'))
56
+
57
+ if not g.current_user.get('is_verified', False):
58
+ if request.path.startswith('/api/'):
59
+ return jsonify({'success': False, 'error': 'Account not verified'}), 403
60
+ else:
61
+ abort(403)
62
+
63
+ return f(*args, **kwargs)
64
+ return decorated_function
65
+
66
+
67
+ def require_permission(permission: str) -> Callable:
68
+ """Decorator to require specific permission"""
69
+ def decorator(f: Callable) -> Callable:
70
+ @wraps(f)
71
+ def decorated_function(*args, **kwargs):
72
+ if not hasattr(g, 'current_user') or not g.current_user:
73
+ if request.path.startswith('/api/'):
74
+ return jsonify({'success': False, 'error': 'Authentication required'}), 401
75
+ else:
76
+ return redirect(url_for('login'))
77
+
78
+ # Check permission (this would need to be implemented in the API)
79
+ # For now, check if user is admin
80
+ user_role = g.current_user.get('role')
81
+ if user_role != 'admin':
82
+ if request.path.startswith('/api/'):
83
+ return jsonify({'success': False, 'error': 'Insufficient permissions'}), 403
84
+ else:
85
+ abort(403)
86
+
87
+ return f(*args, **kwargs)
88
+ return decorated_function
89
+ return decorator
90
+
91
+
92
+ def optional_auth(f: Callable) -> Callable:
93
+ """Decorator that makes authentication optional"""
94
+ @wraps(f)
95
+ def decorated_function(*args, **kwargs):
96
+ # User may or may not be authenticated
97
+ return f(*args, **kwargs)
98
+ return decorated_function
99
+
100
+
101
+ def rate_limit(limit: int, window: int = 60) -> Callable:
102
+ """Decorator for rate limiting"""
103
+ def decorator(f: Callable) -> Callable:
104
+ @wraps(f)
105
+ def decorated_function(*args, **kwargs):
106
+ # This is a placeholder - implement actual rate limiting
107
+ return f(*args, **kwargs)
108
+ return decorated_function
109
+ return decorator
authix/exceptions.py ADDED
@@ -0,0 +1,42 @@
1
+ """
2
+ SecureAuth Exceptions
3
+ Custom exceptions for SecureAuth SDK
4
+ """
5
+
6
+
7
+ class SecureAuthError(Exception):
8
+ """Base exception for SecureAuth errors"""
9
+ pass
10
+
11
+
12
+ class SecureAuthException(SecureAuthError):
13
+ """Exception for SecureAuth API errors"""
14
+ def __init__(self, message: str, status_code: int = None, response_data: dict = None):
15
+ super().__init__(message)
16
+ self.status_code = status_code
17
+ self.response_data = response_data or {}
18
+
19
+
20
+ class AuthenticationError(SecureAuthError):
21
+ """Exception for authentication failures"""
22
+ pass
23
+
24
+
25
+ class AuthorizationError(SecureAuthError):
26
+ """Exception for authorization failures"""
27
+ pass
28
+
29
+
30
+ class ConfigurationError(SecureAuthError):
31
+ """Exception for configuration errors"""
32
+ pass
33
+
34
+
35
+ class NetworkError(SecureAuthError):
36
+ """Exception for network-related errors"""
37
+ pass
38
+
39
+
40
+ class ValidationError(SecureAuthError):
41
+ """Exception for validation errors"""
42
+ pass