cnhkmcp 1.1.6__tar.gz → 1.1.7__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cnhkmcp
3
- Version: 1.1.6
3
+ Version: 1.1.7
4
4
  Summary: A comprehensive Model Context Protocol (MCP) server for quantitative trading platform integration
5
5
  Home-page: https://github.com/cnhk/cnhkmcp
6
6
  Author: CNHK
@@ -50,7 +50,7 @@ from .untracked.forum_functions import (
50
50
  read_full_forum_post
51
51
  )
52
52
 
53
- __version__ = "1.1.6"
53
+ __version__ = "1.1.7"
54
54
  __author__ = "CNHK"
55
55
  __email__ = "cnhk@example.com"
56
56
 
@@ -81,8 +81,8 @@ class BrainApiClient:
81
81
  print(f"[{level}] {message}", file=sys.stderr)
82
82
 
83
83
  async def authenticate(self, email: str, password: str) -> Dict[str, Any]:
84
- """Authenticate with WorldQuant BRAIN platform using Basic Authentication."""
85
- self.log("🔐 Starting Basic Authentication process...", "INFO")
84
+ """Authenticate with WorldQuant BRAIN platform with biometric support."""
85
+ self.log("🔐 Starting Authentication process...", "INFO")
86
86
 
87
87
  try:
88
88
  # Store credentials for potential re-authentication
@@ -106,7 +106,7 @@ class BrainApiClient:
106
106
 
107
107
  # Check for successful authentication (status code 201)
108
108
  if response.status_code == 201:
109
- self.log("✅ Basic Authentication successful", "SUCCESS")
109
+ self.log("✅ Authentication successful", "SUCCESS")
110
110
 
111
111
  # Check if JWT token was automatically stored by session
112
112
  jwt_token = self.session.cookies.get('t')
@@ -120,10 +120,26 @@ class BrainApiClient:
120
120
  'user': {'email': email},
121
121
  'status': 'authenticated',
122
122
  'permissions': ['read', 'write'],
123
- 'message': 'Basic Authentication successful',
123
+ 'message': 'Authentication successful',
124
124
  'status_code': response.status_code,
125
125
  'has_jwt': jwt_token is not None
126
126
  }
127
+
128
+ # Check if biometric authentication is required (401 with persona)
129
+ elif response.status_code == 401:
130
+ www_auth = response.headers.get("WWW-Authenticate")
131
+ location = response.headers.get("Location")
132
+
133
+ if www_auth == "persona" and location:
134
+ self.log("🔴 Biometric authentication required", "INFO")
135
+
136
+ # Handle biometric authentication
137
+ from urllib.parse import urljoin
138
+ biometric_url = urljoin(response.url, location)
139
+
140
+ return await self._handle_biometric_auth(biometric_url, email)
141
+ else:
142
+ raise Exception("Incorrect email or password")
127
143
  else:
128
144
  raise Exception(f"Authentication failed with status code: {response.status_code}")
129
145
 
@@ -134,6 +150,97 @@ class BrainApiClient:
134
150
  self.log(f"❌ Authentication failed: {str(e)}", "ERROR")
135
151
  raise
136
152
 
153
+ async def _handle_biometric_auth(self, biometric_url: str, email: str) -> Dict[str, Any]:
154
+ """Handle biometric authentication using browser automation."""
155
+ self.log("🌐 Starting biometric authentication...", "INFO")
156
+
157
+ try:
158
+ # Import selenium for browser automation
159
+ from selenium import webdriver
160
+ from selenium.webdriver.chrome.options import Options
161
+ import time
162
+
163
+ # Setup Chrome options
164
+ options = Options()
165
+ options.add_argument('--no-sandbox')
166
+ options.add_argument('--disable-dev-shm-usage')
167
+
168
+ driver = None
169
+ try:
170
+ # Open browser with timeout
171
+ driver = webdriver.Chrome(options=options)
172
+ # Set a short timeout so it doesn't wait forever
173
+ driver.set_page_load_timeout(80) # Only wait 5 seconds
174
+
175
+ self.log("🌐 Opening browser for biometric authentication...", "INFO")
176
+
177
+ # Try to open the URL but handle timeout
178
+ try:
179
+ driver.get(biometric_url)
180
+ self.log("✅ Browser page loaded successfully", "SUCCESS")
181
+ except Exception as timeout_error:
182
+ self.log(f"⚠️ Page load timeout (expected): {str(timeout_error)[:50]}...", "WARNING")
183
+ self.log("✅ Browser window is open for biometric authentication", "INFO")
184
+
185
+ # Print instructions
186
+ print("\n" + "="*60, file=sys.stderr)
187
+ print("🔒 BIOMETRIC AUTHENTICATION REQUIRED", file=sys.stderr)
188
+ print("="*60, file=sys.stderr)
189
+ print("🌐 Browser window is open with biometric authentication page", file=sys.stderr)
190
+ print("🔧 Complete the biometric authentication in the browser", file=sys.stderr)
191
+ print("⏳ The system will automatically check when you're done...", file=sys.stderr)
192
+ print("="*60, file=sys.stderr)
193
+
194
+ # Keep checking until authentication is complete
195
+ max_attempts = 60 # 5 minutes maximum (60 * 5 seconds)
196
+ attempt = 0
197
+
198
+ while attempt < max_attempts:
199
+ time.sleep(5) # Check every 5 seconds
200
+ attempt += 1
201
+
202
+ # Check if authentication completed
203
+ check_response = self.session.post(biometric_url)
204
+ self.log(f"🔄 Checking authentication status (attempt {attempt}/{max_attempts}): {check_response.status_code}", "INFO")
205
+
206
+ if check_response.status_code == 201:
207
+ self.log("✅ Biometric authentication successful!", "SUCCESS")
208
+
209
+ # Close browser
210
+ driver.quit()
211
+
212
+ # Check JWT token
213
+ jwt_token = self.session.cookies.get('t')
214
+ if jwt_token:
215
+ self.log("✅ JWT token received", "SUCCESS")
216
+
217
+ # Return success response
218
+ return {
219
+ 'user': {'email': email},
220
+ 'status': 'authenticated',
221
+ 'permissions': ['read', 'write'],
222
+ 'message': 'Biometric authentication successful',
223
+ 'status_code': check_response.status_code,
224
+ 'has_jwt': jwt_token is not None
225
+ }
226
+
227
+ # If we get here, authentication timed out
228
+ if driver:
229
+ driver.quit()
230
+ raise Exception("Biometric authentication timed out")
231
+
232
+ except Exception as driver_error:
233
+ if driver:
234
+ try:
235
+ driver.quit()
236
+ except:
237
+ pass
238
+ raise Exception(f"Browser automation error: {driver_error}")
239
+
240
+ except Exception as e:
241
+ self.log(f"❌ Biometric authentication failed: {str(e)}", "ERROR")
242
+ raise
243
+
137
244
  async def is_authenticated(self) -> bool:
138
245
  """Check if currently authenticated using JWT token."""
139
246
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cnhkmcp
3
- Version: 1.1.6
3
+ Version: 1.1.7
4
4
  Summary: A comprehensive Model Context Protocol (MCP) server for quantitative trading platform integration
5
5
  Home-page: https://github.com/cnhk/cnhkmcp
6
6
  Author: CNHK
@@ -13,7 +13,7 @@ def read_requirements():
13
13
 
14
14
  setup(
15
15
  name="cnhkmcp",
16
- version="1.1.6",
16
+ version="1.1.7",
17
17
  author="CNHK",
18
18
  author_email="cnhk@example.com",
19
19
  description="A comprehensive Model Context Protocol (MCP) server for quantitative trading platform integration",
File without changes
File without changes
File without changes
File without changes
File without changes