unitlab 2.3.14__tar.gz → 2.3.16__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.
- {unitlab-2.3.14/src/unitlab.egg-info → unitlab-2.3.16}/PKG-INFO +1 -1
- {unitlab-2.3.14 → unitlab-2.3.16}/setup.py +1 -1
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab/cloudflare_api_tunnel.py +22 -3
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab/main.py +18 -4
- {unitlab-2.3.14 → unitlab-2.3.16/src/unitlab.egg-info}/PKG-INFO +1 -1
- {unitlab-2.3.14 → unitlab-2.3.16}/LICENSE.md +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/README.md +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/setup.cfg +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab/__init__.py +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab/__main__.py +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab/binary_manager.py +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab/client.py +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab/exceptions.py +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab/tunnel_config.py +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab/tunnel_service_token.py +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab/utils.py +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab.egg-info/SOURCES.txt +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab.egg-info/dependency_links.txt +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab.egg-info/entry_points.txt +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab.egg-info/requires.txt +0 -0
- {unitlab-2.3.14 → unitlab-2.3.16}/src/unitlab.egg-info/top_level.txt +0 -0
@@ -231,9 +231,12 @@ class CloudflareAPITunnel:
|
|
231
231
|
# Create new tunnel
|
232
232
|
print(f"📦 Creating new tunnel: {tunnel_name}")
|
233
233
|
create_url = f"{self.api_base}/accounts/{self.account_id}/tunnels"
|
234
|
+
# Generate secret first
|
235
|
+
tunnel_secret = os.urandom(32).hex()
|
236
|
+
|
234
237
|
create_data = {
|
235
238
|
"name": tunnel_name,
|
236
|
-
"tunnel_secret":
|
239
|
+
"tunnel_secret": tunnel_secret
|
237
240
|
}
|
238
241
|
|
239
242
|
create_response = requests.post(create_url, headers=self.headers, json=create_data)
|
@@ -242,6 +245,9 @@ class CloudflareAPITunnel:
|
|
242
245
|
existing_tunnel = create_response.json()['result']
|
243
246
|
print(f"✅ Created tunnel: {tunnel_name}")
|
244
247
|
|
248
|
+
# Add the secret to the tunnel info (API doesn't return it)
|
249
|
+
existing_tunnel['tunnel_secret'] = tunnel_secret
|
250
|
+
|
245
251
|
# Save credentials for this tunnel
|
246
252
|
self._save_tunnel_credentials(existing_tunnel)
|
247
253
|
|
@@ -308,19 +314,32 @@ class CloudflareAPITunnel:
|
|
308
314
|
def _save_tunnel_credentials(self, tunnel_info):
|
309
315
|
"""
|
310
316
|
Save tunnel credentials locally for this device
|
317
|
+
Credentials must be base64 encoded for cloudflared
|
311
318
|
"""
|
319
|
+
import base64
|
320
|
+
import json
|
321
|
+
|
312
322
|
creds_dir = Path.home() / '.cloudflared'
|
313
323
|
creds_dir.mkdir(exist_ok=True)
|
314
324
|
|
315
325
|
creds_file = creds_dir / f"{tunnel_info['id']}.json"
|
316
326
|
|
327
|
+
# Get the secret - it should be hex string
|
328
|
+
secret_hex = tunnel_info.get('tunnel_secret') or tunnel_info.get('secret')
|
329
|
+
if secret_hex:
|
330
|
+
# Convert hex to bytes then to base64
|
331
|
+
secret_bytes = bytes.fromhex(secret_hex)
|
332
|
+
secret_b64 = base64.b64encode(secret_bytes).decode('ascii')
|
333
|
+
else:
|
334
|
+
print("⚠️ No tunnel secret found")
|
335
|
+
return None
|
336
|
+
|
317
337
|
credentials = {
|
318
338
|
"AccountTag": self.account_id,
|
319
|
-
"TunnelSecret":
|
339
|
+
"TunnelSecret": secret_b64, # Must be base64!
|
320
340
|
"TunnelID": tunnel_info['id']
|
321
341
|
}
|
322
342
|
|
323
|
-
import json
|
324
343
|
with open(creds_file, 'w') as f:
|
325
344
|
json.dump(credentials, f)
|
326
345
|
|
@@ -146,13 +146,27 @@ def run_agent(
|
|
146
146
|
if not device_id:
|
147
147
|
import uuid
|
148
148
|
import platform
|
149
|
+
from pathlib import Path
|
150
|
+
|
149
151
|
# Try environment variable first
|
150
152
|
device_id = os.getenv('DEVICE_ID')
|
151
153
|
if not device_id:
|
152
|
-
#
|
153
|
-
|
154
|
-
|
155
|
-
|
154
|
+
# Try to load saved device ID
|
155
|
+
device_id_file = Path.home() / '.unitlab' / 'device_id'
|
156
|
+
device_id_file.parent.mkdir(exist_ok=True, parents=True)
|
157
|
+
|
158
|
+
if device_id_file.exists():
|
159
|
+
device_id = device_id_file.read_text().strip()
|
160
|
+
print(f"📌 Using saved device ID: {device_id}")
|
161
|
+
else:
|
162
|
+
# Generate a unique ID based on hostname and random UUID
|
163
|
+
hostname = platform.node().replace('.', '-').replace(' ', '-')[:20]
|
164
|
+
random_suffix = str(uuid.uuid4())[:8]
|
165
|
+
device_id = f"{hostname}-{random_suffix}"
|
166
|
+
|
167
|
+
# Save for future runs
|
168
|
+
device_id_file.write_text(device_id)
|
169
|
+
print(f"📝 Generated and saved device ID: {device_id}")
|
156
170
|
|
157
171
|
|
158
172
|
# Create client and initialize device agent
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|