unitlab 2.3.38__tar.gz → 2.3.40__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.38/src/unitlab.egg-info → unitlab-2.3.40}/PKG-INFO +1 -1
- {unitlab-2.3.38 → unitlab-2.3.40}/setup.py +1 -1
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab/persistent_tunnel.py +48 -68
- {unitlab-2.3.38 → unitlab-2.3.40/src/unitlab.egg-info}/PKG-INFO +1 -1
- {unitlab-2.3.38 → unitlab-2.3.40}/LICENSE.md +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/README.md +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/setup.cfg +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab/__init__.py +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab/__main__.py +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab/client.py +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab/exceptions.py +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab/main.py +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab/utils.py +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab.egg-info/SOURCES.txt +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab.egg-info/dependency_links.txt +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab.egg-info/entry_points.txt +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab.egg-info/requires.txt +0 -0
- {unitlab-2.3.38 → unitlab-2.3.40}/src/unitlab.egg-info/top_level.txt +0 -0
@@ -56,24 +56,7 @@ class PersistentTunnel:
|
|
56
56
|
self.jupyter_process = None
|
57
57
|
self.tunnel_process = None
|
58
58
|
|
59
|
-
|
60
|
-
"""Get Zone ID for unitlab-ai.com"""
|
61
|
-
print("🔍 Getting Zone ID for {}...".format(self.domain))
|
62
|
-
|
63
|
-
url = "https://api.cloudflare.com/client/v4/zones"
|
64
|
-
headers = self._get_headers()
|
65
|
-
params = {"name": self.domain}
|
66
|
-
|
67
|
-
response = requests.get(url, headers=headers, params=params)
|
68
|
-
if response.status_code == 200:
|
69
|
-
data = response.json()
|
70
|
-
if data["result"]:
|
71
|
-
self.cf_zone_id = data["result"][0]["id"]
|
72
|
-
print("✅ Zone ID: {}".format(self.cf_zone_id))
|
73
|
-
return self.cf_zone_id
|
74
|
-
|
75
|
-
print("❌ Could not get Zone ID")
|
76
|
-
return None
|
59
|
+
|
77
60
|
|
78
61
|
def _get_headers(self):
|
79
62
|
"""Get API headers for Global API Key"""
|
@@ -85,32 +68,14 @@ class PersistentTunnel:
|
|
85
68
|
}
|
86
69
|
|
87
70
|
def get_or_create_tunnel(self):
|
88
|
-
"""
|
89
|
-
#
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
#
|
96
|
-
response = requests.get(list_url, headers=headers)
|
97
|
-
if response.status_code == 200:
|
98
|
-
tunnels = response.json().get("result", [])
|
99
|
-
for tunnel in tunnels:
|
100
|
-
if tunnel["name"] == self.tunnel_name:
|
101
|
-
print("✅ Found existing tunnel: {}".format(tunnel["id"]))
|
102
|
-
self.tunnel_id = tunnel["id"]
|
103
|
-
|
104
|
-
# Tunnel exists, create a new one with unique name
|
105
|
-
print("⚠️ Tunnel with this name already exists")
|
106
|
-
import uuid
|
107
|
-
unique_suffix = str(uuid.uuid4())[:8]
|
108
|
-
self.tunnel_name = "agent-{}-{}".format(self.device_id, unique_suffix)
|
109
|
-
print("🔄 Creating new tunnel with unique name: {}".format(self.tunnel_name))
|
110
|
-
# Don't break, let it continue to create new tunnel
|
111
|
-
return self.create_new_tunnel()
|
112
|
-
|
113
|
-
# Create new tunnel
|
71
|
+
"""Always create a new tunnel with unique name to avoid conflicts"""
|
72
|
+
# Generate unique tunnel name to avoid conflicts
|
73
|
+
import uuid
|
74
|
+
unique_suffix = str(uuid.uuid4())[:8]
|
75
|
+
self.tunnel_name = "agent-{}-{}".format(self.device_id, unique_suffix)
|
76
|
+
print("🔧 Creating tunnel: {}...".format(self.tunnel_name))
|
77
|
+
|
78
|
+
# Always create new tunnel
|
114
79
|
return self.create_new_tunnel()
|
115
80
|
|
116
81
|
def create_new_tunnel(self):
|
@@ -160,9 +125,7 @@ class PersistentTunnel:
|
|
160
125
|
|
161
126
|
print("🔧 Creating DNS records...")
|
162
127
|
|
163
|
-
#
|
164
|
-
if self.cf_zone_id == "NEED_ZONE_ID_FOR_1SCAN_UZ":
|
165
|
-
self.get_zone_id()
|
128
|
+
# self.get_zone_id()
|
166
129
|
|
167
130
|
url = "https://api.cloudflare.com/client/v4/zones/{}/dns_records".format(self.cf_zone_id)
|
168
131
|
headers = self._get_headers()
|
@@ -186,7 +149,32 @@ class PersistentTunnel:
|
|
186
149
|
print("❌ Failed to create main DNS: {}".format(response.text[:200]))
|
187
150
|
return False
|
188
151
|
|
189
|
-
#
|
152
|
+
# First, check if SSH DNS record exists and delete it
|
153
|
+
print("🔍 Checking for existing SSH DNS record: {}.{}".format(self.ssh_subdomain, self.domain))
|
154
|
+
list_url = "{}?name={}.{}".format(url, self.ssh_subdomain, self.domain)
|
155
|
+
list_response = requests.get(list_url, headers=headers)
|
156
|
+
|
157
|
+
if list_response.status_code == 200:
|
158
|
+
records = list_response.json().get("result", [])
|
159
|
+
print("Found {} existing DNS records".format(len(records)))
|
160
|
+
print('this is new version')
|
161
|
+
for record in records:
|
162
|
+
if record["name"] == "{}.{}".format(self.ssh_subdomain, self.domain):
|
163
|
+
record_id = record["id"]
|
164
|
+
print("🗑️ Deleting old SSH DNS record: {}".format(record_id))
|
165
|
+
delete_url = "{}/{}".format(url, record_id)
|
166
|
+
delete_response = requests.delete(delete_url, headers=headers)
|
167
|
+
if delete_response.status_code in [200, 204]:
|
168
|
+
print("✅ Deleted old SSH DNS record")
|
169
|
+
else:
|
170
|
+
print("⚠️ Could not delete old SSH DNS record: {}".format(delete_response.text[:200]))
|
171
|
+
else:
|
172
|
+
print("⚠️ Could not list DNS records: {}".format(list_response.text[:200]))
|
173
|
+
|
174
|
+
# Wait a moment for DNS deletion to propagate
|
175
|
+
time.sleep(2)
|
176
|
+
|
177
|
+
# Create new SSH subdomain record pointing to new tunnel
|
190
178
|
ssh_data = {
|
191
179
|
"type": "CNAME",
|
192
180
|
"name": self.ssh_subdomain,
|
@@ -195,31 +183,22 @@ class PersistentTunnel:
|
|
195
183
|
"ttl": 1
|
196
184
|
}
|
197
185
|
|
186
|
+
print("📝 Creating SSH DNS record: {} -> {}".format(self.ssh_subdomain, self.tunnel_id))
|
198
187
|
ssh_response = requests.post(url, headers=headers, json=ssh_data)
|
199
188
|
|
200
189
|
if ssh_response.status_code in [200, 201]:
|
201
190
|
print("✅ SSH DNS record created: {}.{}".format(self.ssh_subdomain, self.domain))
|
202
|
-
|
203
|
-
print("⚠️ SSH DNS record already exists, deleting and recreating...")
|
204
|
-
# Delete the old record and create new one
|
205
|
-
list_url = "{}?name={}.{}".format(url, self.ssh_subdomain, self.domain)
|
206
|
-
list_response = requests.get(list_url, headers=headers)
|
207
|
-
if list_response.status_code == 200:
|
208
|
-
records = list_response.json().get("result", [])
|
209
|
-
if records:
|
210
|
-
record_id = records[0]["id"]
|
211
|
-
delete_url = "{}/{}".format(url, record_id)
|
212
|
-
requests.delete(delete_url, headers=headers)
|
213
|
-
print("Deleted old SSH DNS record")
|
214
|
-
# Try again
|
215
|
-
ssh_response = requests.post(url, headers=headers, json=ssh_data)
|
216
|
-
if ssh_response.status_code in [200, 201]:
|
217
|
-
print("✅ SSH DNS record recreated: {}.{}".format(self.ssh_subdomain, self.domain))
|
218
|
-
else:
|
219
|
-
print("❌ Failed to recreate SSH DNS: {}".format(ssh_response.text[:200]))
|
191
|
+
print(" Points to: {}.cfargotunnel.com".format(self.tunnel_id))
|
220
192
|
else:
|
221
|
-
print("❌
|
222
|
-
#
|
193
|
+
print("❌ Failed to create SSH DNS: Status {} - {}".format(ssh_response.status_code, ssh_response.text))
|
194
|
+
# Try to parse error
|
195
|
+
try:
|
196
|
+
error_data = ssh_response.json()
|
197
|
+
if "errors" in error_data:
|
198
|
+
for error in error_data["errors"]:
|
199
|
+
print(" Error: {}".format(error.get("message", error)))
|
200
|
+
except:
|
201
|
+
pass
|
223
202
|
|
224
203
|
return True
|
225
204
|
|
@@ -261,6 +240,7 @@ class PersistentTunnel:
|
|
261
240
|
|
262
241
|
policy_response = requests.post(policy_url, headers=headers, json=policy_data)
|
263
242
|
|
243
|
+
|
264
244
|
if policy_response.status_code in [200, 201]:
|
265
245
|
print("✅ Bypass policy created - SSH is publicly accessible")
|
266
246
|
return True
|
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
|