unitlab 2.3.9__tar.gz → 2.3.11__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.1
2
2
  Name: unitlab
3
- Version: 2.3.9
3
+ Version: 2.3.11
4
4
  Home-page: https://github.com/teamunitlab/unitlab-sdk
5
5
  Author: Unitlab Inc.
6
6
  Author-email: team@unitlab.ai
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
2
2
 
3
3
  setup(
4
4
  name="unitlab",
5
- version="2.3.9",
5
+ version="2.3.11",
6
6
  license="MIT",
7
7
  author="Unitlab Inc.",
8
8
  author_email="team@unitlab.ai",
@@ -89,6 +89,12 @@ class CloudflaredBinaryManager:
89
89
 
90
90
  def _download_binary(self, info, target_path):
91
91
  """Download and verify binary"""
92
+
93
+ # Create SSL context to handle certificate issues
94
+ import ssl
95
+ ssl_context = ssl.create_default_context()
96
+ ssl_context.check_hostname = False
97
+ ssl_context.verify_mode = ssl.CERT_NONE
92
98
 
93
99
  # Download with progress bar
94
100
  def download_progress(block_num, block_size, total_size):
@@ -102,12 +108,23 @@ class CloudflaredBinaryManager:
102
108
  temp_file = target_path.with_suffix('.tmp')
103
109
 
104
110
  try:
105
- # Download file
106
- urllib.request.urlretrieve(
107
- info['url'],
108
- temp_file,
109
- reporthook=download_progress
110
- )
111
+ # Download file with SSL context
112
+ req = urllib.request.Request(info['url'], headers={'User-Agent': 'Mozilla/5.0'})
113
+ with urllib.request.urlopen(req, context=ssl_context) as response:
114
+ total_size = int(response.headers.get('Content-Length', 0))
115
+
116
+ with open(temp_file, 'wb') as f:
117
+ downloaded = 0
118
+ block_size = 8192
119
+ while True:
120
+ chunk = response.read(block_size)
121
+ if not chunk:
122
+ break
123
+ f.write(chunk)
124
+ downloaded += len(chunk)
125
+ if total_size > 0:
126
+ percent = min(downloaded * 100 / total_size, 100)
127
+ print(f"Downloading: {percent:.0f}%", end='\r')
111
128
  print("\n✓ Download complete")
112
129
 
113
130
  # Handle compressed files (macOS .tgz)
@@ -53,12 +53,14 @@ class CloudflareAPITunnel:
53
53
  "Content-Type": "application/json"
54
54
  } if self.api_token else {}
55
55
 
56
- # URLs for services
56
+ # URLs for services - simplified for Jupyter only
57
57
  self.jupyter_subdomain = f"j{self.clean_device_id}"
58
- self.ssh_subdomain = f"s{self.clean_device_id}"
59
58
  self.jupyter_url = f"https://{self.jupyter_subdomain}.{self.base_domain}"
59
+
60
+ # Keep SSH URLs for compatibility but they won't work yet
61
+ self.ssh_subdomain = f"s{self.clean_device_id}"
60
62
  self.ssh_hostname = f"{self.ssh_subdomain}.{self.base_domain}"
61
- self.ssh_url = self.ssh_hostname # For backward compatibility
63
+ self.ssh_url = self.ssh_hostname
62
64
 
63
65
  self.tunnel_process = None
64
66
  self.created_dns_records = []
@@ -220,11 +222,10 @@ class CloudflareAPITunnel:
220
222
  if not cloudflared_path:
221
223
  raise RuntimeError("Failed to obtain cloudflared binary")
222
224
 
223
- # Use the service token - hardcoded for zero-config experience
224
- # This token can ONLY run the tunnel, cannot modify or delete it (safe to embed)
225
- service_token = "eyJhIjoiYzkxMTkyYWUyMGE1ZDQzZjY1ZTA4NzU1MGQ4ZGM4OWIiLCJ0IjoiMDc3N2ZjMTAtNDljNC00NzJkLTg2NjEtZjYwZDgwZDYxODRkIiwicyI6Ik9XRTNaak5tTVdVdE1tWTRaUzAwTmpoakxUazBaalF0WXpjek1tSm1ZVGt4WlRRMCJ9"
225
+ # Use service token - simple and reliable
226
+ # The dashboard must have *.1scan.uz -> localhost:8888 configured
227
+ service_token = "eyJhIjoiYzkxMTkyYWUyMGE1ZDQzZjY1ZTA4NzU1MGQ4ZGM4OWIiLCJ0IjoiMDc3N2ZjMTAtNDljNC00NzJkLTg2NjEtZjYwZDgwZDYxODRkIiwicyI6Ik9XRTNaak5tTVdVdE1tWTRaUzAwTmpoakxTazBaalF0WXpjek1tSm1ZVGt4WlRRMCJ9"
226
228
 
227
- # Start tunnel with service token
228
229
  cmd = [
229
230
  cloudflared_path,
230
231
  "tunnel",
@@ -296,6 +297,12 @@ class CloudflareAPITunnel:
296
297
  # Direct download fallback - simplified version
297
298
  import platform
298
299
  import urllib.request
300
+ import ssl
301
+
302
+ # Create SSL context that handles certificate issues
303
+ ssl_context = ssl.create_default_context()
304
+ ssl_context.check_hostname = False
305
+ ssl_context.verify_mode = ssl.CERT_NONE
299
306
 
300
307
  cache_dir = Path.home() / '.unitlab' / 'bin'
301
308
  cache_dir.mkdir(parents=True, exist_ok=True)
@@ -330,8 +337,25 @@ class CloudflareAPITunnel:
330
337
  raise RuntimeError(f"Unsupported platform: {system}")
331
338
 
332
339
  try:
333
- # Download the file
334
- urllib.request.urlretrieve(url, cloudflared_path)
340
+ # Download the file with SSL context
341
+ req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
342
+
343
+ # Special handling for macOS .tgz files
344
+ if system == 'darwin':
345
+ import tarfile
346
+ import io
347
+
348
+ with urllib.request.urlopen(req, context=ssl_context) as response:
349
+ data = response.read()
350
+
351
+ # Extract from tar.gz
352
+ with tarfile.open(fileobj=io.BytesIO(data), mode='r:gz') as tar:
353
+ tar.extract('cloudflared', cache_dir)
354
+ else:
355
+ # Direct binary download for Linux/Windows
356
+ with urllib.request.urlopen(req, context=ssl_context) as response:
357
+ with open(cloudflared_path, 'wb') as out_file:
358
+ out_file.write(response.read())
335
359
 
336
360
  # Make executable on Unix
337
361
  if system != 'windows':
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unitlab
3
- Version: 2.3.9
3
+ Version: 2.3.11
4
4
  Home-page: https://github.com/teamunitlab/unitlab-sdk
5
5
  Author: Unitlab Inc.
6
6
  Author-email: team@unitlab.ai
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes