unitlab 2.3.27__py3-none-any.whl → 2.3.29__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.
- unitlab/api_tunnel.py +238 -0
- unitlab/auto_tunnel.py +174 -0
- unitlab/client.py +31 -9
- unitlab/dynamic_tunnel.py +272 -0
- unitlab/easy_tunnel.py +210 -0
- unitlab/persistent_tunnel.py +348 -0
- unitlab/simple_tunnel.py +48 -1
- {unitlab-2.3.27.dist-info → unitlab-2.3.29.dist-info}/METADATA +1 -1
- unitlab-2.3.29.dist-info/RECORD +23 -0
- unitlab-2.3.27.dist-info/RECORD +0 -18
- {unitlab-2.3.27.dist-info → unitlab-2.3.29.dist-info}/LICENSE.md +0 -0
- {unitlab-2.3.27.dist-info → unitlab-2.3.29.dist-info}/WHEEL +0 -0
- {unitlab-2.3.27.dist-info → unitlab-2.3.29.dist-info}/entry_points.txt +0 -0
- {unitlab-2.3.27.dist-info → unitlab-2.3.29.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,348 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Persistent Tunnel - Each device gets deviceid.1scan.uz
|
4
|
+
Uses Cloudflare API to create named tunnels
|
5
|
+
"""
|
6
|
+
|
7
|
+
import subprocess
|
8
|
+
import requests
|
9
|
+
import json
|
10
|
+
import time
|
11
|
+
import os
|
12
|
+
import base64
|
13
|
+
|
14
|
+
class PersistentTunnel:
|
15
|
+
def __init__(self, device_id=None):
|
16
|
+
"""Initialize with device ID"""
|
17
|
+
|
18
|
+
# Cloudflare credentials (hardcoded for simplicity)
|
19
|
+
self.cf_email = "uone2323@gmail.com"
|
20
|
+
self.cf_api_key = "1c634bd17ca6ade0eb91966323589fd98c72e" # Global API Key
|
21
|
+
|
22
|
+
# Account and Zone IDs
|
23
|
+
self.cf_account_id = "c91192ae20a5d43f65e087550d8dc89b" # Your account ID
|
24
|
+
self.cf_zone_id = "78182c3883adad79d8f1026851a68176" # Zone ID for 1scan.uz
|
25
|
+
|
26
|
+
# Clean device ID for subdomain
|
27
|
+
if device_id:
|
28
|
+
self.device_id = device_id.replace('-', '').replace('_', '').replace('.', '').lower()[:20]
|
29
|
+
else:
|
30
|
+
import uuid
|
31
|
+
self.device_id = str(uuid.uuid4())[:8]
|
32
|
+
|
33
|
+
self.tunnel_name = "agent-{}".format(self.device_id)
|
34
|
+
self.subdomain = self.device_id
|
35
|
+
self.domain = "1scan.uz"
|
36
|
+
self.jupyter_url = "https://{}.{}".format(self.subdomain, self.domain)
|
37
|
+
|
38
|
+
self.tunnel_id = None
|
39
|
+
self.tunnel_credentials = None
|
40
|
+
self.jupyter_process = None
|
41
|
+
self.tunnel_process = None
|
42
|
+
|
43
|
+
def get_zone_id(self):
|
44
|
+
"""Get Zone ID for 1scan.uz"""
|
45
|
+
print("🔍 Getting Zone ID for {}...".format(self.domain))
|
46
|
+
|
47
|
+
url = "https://api.cloudflare.com/client/v4/zones"
|
48
|
+
headers = self._get_headers()
|
49
|
+
params = {"name": self.domain}
|
50
|
+
|
51
|
+
response = requests.get(url, headers=headers, params=params)
|
52
|
+
if response.status_code == 200:
|
53
|
+
data = response.json()
|
54
|
+
if data["result"]:
|
55
|
+
self.cf_zone_id = data["result"][0]["id"]
|
56
|
+
print("✅ Zone ID: {}".format(self.cf_zone_id))
|
57
|
+
return self.cf_zone_id
|
58
|
+
|
59
|
+
print("❌ Could not get Zone ID")
|
60
|
+
return None
|
61
|
+
|
62
|
+
def _get_headers(self):
|
63
|
+
"""Get API headers for Global API Key"""
|
64
|
+
return {
|
65
|
+
"X-Auth-Email": self.cf_email,
|
66
|
+
"X-Auth-Key": self.cf_api_key,
|
67
|
+
"Content-Type": "application/json"
|
68
|
+
}
|
69
|
+
|
70
|
+
def create_tunnel(self):
|
71
|
+
"""Create a new tunnel via API"""
|
72
|
+
print("🔧 Creating tunnel: {}...".format(self.tunnel_name))
|
73
|
+
|
74
|
+
# Generate random tunnel secret (32 bytes)
|
75
|
+
import secrets
|
76
|
+
tunnel_secret = base64.b64encode(secrets.token_bytes(32)).decode()
|
77
|
+
|
78
|
+
url = "https://api.cloudflare.com/client/v4/accounts/{}/cfd_tunnel".format(self.cf_account_id)
|
79
|
+
headers = self._get_headers()
|
80
|
+
|
81
|
+
data = {
|
82
|
+
"name": self.tunnel_name,
|
83
|
+
"tunnel_secret": tunnel_secret
|
84
|
+
}
|
85
|
+
|
86
|
+
response = requests.post(url, headers=headers, json=data)
|
87
|
+
|
88
|
+
if response.status_code in [200, 201]:
|
89
|
+
result = response.json()["result"]
|
90
|
+
self.tunnel_id = result["id"]
|
91
|
+
|
92
|
+
# Create credentials JSON
|
93
|
+
self.tunnel_credentials = {
|
94
|
+
"AccountTag": self.cf_account_id,
|
95
|
+
"TunnelSecret": tunnel_secret,
|
96
|
+
"TunnelID": self.tunnel_id
|
97
|
+
}
|
98
|
+
|
99
|
+
# Save credentials to file
|
100
|
+
cred_file = "/tmp/tunnel-{}.json".format(self.tunnel_id)
|
101
|
+
with open(cred_file, 'w') as f:
|
102
|
+
json.dump(self.tunnel_credentials, f)
|
103
|
+
|
104
|
+
print("✅ Tunnel created: {}".format(self.tunnel_id))
|
105
|
+
return cred_file
|
106
|
+
else:
|
107
|
+
print("❌ Failed to create tunnel: {}".format(response.text[:200]))
|
108
|
+
return None
|
109
|
+
|
110
|
+
def create_dns_record(self):
|
111
|
+
"""Create DNS CNAME record"""
|
112
|
+
if not self.tunnel_id:
|
113
|
+
return False
|
114
|
+
|
115
|
+
print("🔧 Creating DNS record: {}.{}...".format(self.subdomain, self.domain))
|
116
|
+
|
117
|
+
# Get zone ID if we don't have it
|
118
|
+
if self.cf_zone_id == "NEED_ZONE_ID_FOR_1SCAN_UZ":
|
119
|
+
self.get_zone_id()
|
120
|
+
|
121
|
+
url = "https://api.cloudflare.com/client/v4/zones/{}/dns_records".format(self.cf_zone_id)
|
122
|
+
headers = self._get_headers()
|
123
|
+
|
124
|
+
data = {
|
125
|
+
"type": "CNAME",
|
126
|
+
"name": self.subdomain,
|
127
|
+
"content": "{}.cfargotunnel.com".format(self.tunnel_id),
|
128
|
+
"proxied": True,
|
129
|
+
"ttl": 1
|
130
|
+
}
|
131
|
+
|
132
|
+
response = requests.post(url, headers=headers, json=data)
|
133
|
+
|
134
|
+
if response.status_code in [200, 201]:
|
135
|
+
print("✅ DNS record created")
|
136
|
+
return True
|
137
|
+
elif "already exists" in response.text:
|
138
|
+
print("⚠️ DNS record already exists")
|
139
|
+
return True
|
140
|
+
else:
|
141
|
+
print("❌ Failed to create DNS: {}".format(response.text[:200]))
|
142
|
+
return False
|
143
|
+
|
144
|
+
def create_tunnel_config(self, cred_file):
|
145
|
+
"""Create tunnel config file"""
|
146
|
+
config = {
|
147
|
+
"ingress": [
|
148
|
+
{
|
149
|
+
"hostname": "{}.{}".format(self.subdomain, self.domain),
|
150
|
+
"service": "http://localhost:8888"
|
151
|
+
},
|
152
|
+
{
|
153
|
+
"service": "http_status:404"
|
154
|
+
}
|
155
|
+
]
|
156
|
+
}
|
157
|
+
|
158
|
+
config_file = "/tmp/tunnel-config-{}.yml".format(self.tunnel_id)
|
159
|
+
with open(config_file, 'w') as f:
|
160
|
+
f.write("tunnel: {}\n".format(self.tunnel_id))
|
161
|
+
f.write("credentials-file: {}\n\n".format(cred_file))
|
162
|
+
f.write("ingress:\n")
|
163
|
+
f.write(" - hostname: {}.{}\n".format(self.subdomain, self.domain))
|
164
|
+
f.write(" service: http://localhost:8888\n")
|
165
|
+
f.write(" - service: http_status:404\n")
|
166
|
+
|
167
|
+
return config_file
|
168
|
+
|
169
|
+
def get_cloudflared_path(self):
|
170
|
+
"""Get or download cloudflared"""
|
171
|
+
import shutil
|
172
|
+
if shutil.which("cloudflared"):
|
173
|
+
return "cloudflared"
|
174
|
+
|
175
|
+
local_bin = os.path.expanduser("~/.local/bin/cloudflared")
|
176
|
+
if os.path.exists(local_bin):
|
177
|
+
return local_bin
|
178
|
+
|
179
|
+
# Download
|
180
|
+
print("📦 Downloading cloudflared...")
|
181
|
+
import platform
|
182
|
+
system = platform.system().lower()
|
183
|
+
arch = "amd64" if "x86" in platform.machine() else "arm64"
|
184
|
+
url = "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-{}".format(arch)
|
185
|
+
|
186
|
+
os.makedirs(os.path.dirname(local_bin), exist_ok=True)
|
187
|
+
subprocess.run("curl -L {} -o {}".format(url, local_bin), shell=True, capture_output=True)
|
188
|
+
subprocess.run("chmod +x {}".format(local_bin), shell=True)
|
189
|
+
return local_bin
|
190
|
+
|
191
|
+
def start_jupyter(self):
|
192
|
+
"""Start Jupyter"""
|
193
|
+
print("🚀 Starting Jupyter...")
|
194
|
+
|
195
|
+
cmd = [
|
196
|
+
"jupyter", "notebook",
|
197
|
+
"--port", "8888",
|
198
|
+
"--no-browser",
|
199
|
+
"--ip", "0.0.0.0",
|
200
|
+
"--NotebookApp.token=''",
|
201
|
+
"--NotebookApp.password=''"
|
202
|
+
]
|
203
|
+
|
204
|
+
self.jupyter_process = subprocess.Popen(
|
205
|
+
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
206
|
+
)
|
207
|
+
|
208
|
+
time.sleep(3)
|
209
|
+
print("✅ Jupyter started")
|
210
|
+
return True
|
211
|
+
|
212
|
+
def start_tunnel(self, config_file):
|
213
|
+
"""Start tunnel with config"""
|
214
|
+
print("🔧 Starting tunnel...")
|
215
|
+
|
216
|
+
cloudflared = self.get_cloudflared_path()
|
217
|
+
|
218
|
+
cmd = [
|
219
|
+
cloudflared,
|
220
|
+
"tunnel",
|
221
|
+
"--config", config_file,
|
222
|
+
"run"
|
223
|
+
]
|
224
|
+
|
225
|
+
self.tunnel_process = subprocess.Popen(
|
226
|
+
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
227
|
+
)
|
228
|
+
|
229
|
+
time.sleep(5)
|
230
|
+
print("✅ Tunnel running at {}".format(self.jupyter_url))
|
231
|
+
return True
|
232
|
+
|
233
|
+
def start(self):
|
234
|
+
"""Main entry point"""
|
235
|
+
try:
|
236
|
+
print("="*50)
|
237
|
+
print("🌐 Persistent Tunnel with API")
|
238
|
+
print("Device: {}".format(self.device_id))
|
239
|
+
print("Target: {}.{}".format(self.subdomain, self.domain))
|
240
|
+
print("="*50)
|
241
|
+
|
242
|
+
# API credentials are hardcoded, so we're ready to go
|
243
|
+
|
244
|
+
# 1. Create tunnel via API
|
245
|
+
cred_file = self.create_tunnel()
|
246
|
+
if not cred_file:
|
247
|
+
print("⚠️ Falling back to quick tunnel")
|
248
|
+
return self.start_quick_tunnel()
|
249
|
+
|
250
|
+
# 2. Create DNS record
|
251
|
+
self.create_dns_record()
|
252
|
+
|
253
|
+
# 3. Create config
|
254
|
+
config_file = self.create_tunnel_config(cred_file)
|
255
|
+
|
256
|
+
# 4. Start services
|
257
|
+
self.start_jupyter()
|
258
|
+
self.start_tunnel(config_file)
|
259
|
+
|
260
|
+
print("\n" + "="*50)
|
261
|
+
print("🎉 SUCCESS! Persistent URL created:")
|
262
|
+
print(" {}".format(self.jupyter_url))
|
263
|
+
print(" Tunnel ID: {}".format(self.tunnel_id))
|
264
|
+
print("="*50)
|
265
|
+
|
266
|
+
return True
|
267
|
+
|
268
|
+
except Exception as e:
|
269
|
+
print("❌ Error: {}".format(e))
|
270
|
+
import traceback
|
271
|
+
traceback.print_exc()
|
272
|
+
self.stop()
|
273
|
+
return False
|
274
|
+
|
275
|
+
def start_quick_tunnel(self):
|
276
|
+
"""Fallback to quick tunnel"""
|
277
|
+
print("🔧 Using quick tunnel (temporary URL)...")
|
278
|
+
|
279
|
+
# Start Jupyter first
|
280
|
+
self.start_jupyter()
|
281
|
+
|
282
|
+
# Start quick tunnel
|
283
|
+
cloudflared = self.get_cloudflared_path()
|
284
|
+
cmd = [cloudflared, "tunnel", "--url", "http://localhost:8888"]
|
285
|
+
|
286
|
+
self.tunnel_process = subprocess.Popen(
|
287
|
+
cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
|
288
|
+
)
|
289
|
+
|
290
|
+
# Get URL from output
|
291
|
+
for _ in range(30):
|
292
|
+
line = self.tunnel_process.stdout.readline()
|
293
|
+
if "trycloudflare.com" in line:
|
294
|
+
import re
|
295
|
+
match = re.search(r'https://[a-zA-Z0-9-]+\.trycloudflare\.com', line)
|
296
|
+
if match:
|
297
|
+
self.jupyter_url = match.group(0)
|
298
|
+
print("✅ Quick tunnel: {}".format(self.jupyter_url))
|
299
|
+
return True
|
300
|
+
time.sleep(0.5)
|
301
|
+
|
302
|
+
return False
|
303
|
+
|
304
|
+
def stop(self):
|
305
|
+
"""Stop everything"""
|
306
|
+
if self.jupyter_process:
|
307
|
+
self.jupyter_process.terminate()
|
308
|
+
if self.tunnel_process:
|
309
|
+
self.tunnel_process.terminate()
|
310
|
+
|
311
|
+
# Optionally delete tunnel when stopping
|
312
|
+
if self.tunnel_id:
|
313
|
+
try:
|
314
|
+
url = "https://api.cloudflare.com/client/v4/accounts/{}/cfd_tunnel/{}".format(
|
315
|
+
self.cf_account_id, self.tunnel_id
|
316
|
+
)
|
317
|
+
requests.delete(url, headers=self._get_headers())
|
318
|
+
print("🗑️ Tunnel deleted")
|
319
|
+
except Exception as e:
|
320
|
+
pass # Ignore cleanup errors
|
321
|
+
|
322
|
+
def run(self):
|
323
|
+
"""Run and keep alive"""
|
324
|
+
try:
|
325
|
+
if self.start():
|
326
|
+
print("\nPress Ctrl+C to stop...")
|
327
|
+
while True:
|
328
|
+
time.sleep(1)
|
329
|
+
except KeyboardInterrupt:
|
330
|
+
print("\n⏹️ Shutting down...")
|
331
|
+
self.stop()
|
332
|
+
|
333
|
+
|
334
|
+
def main():
|
335
|
+
import platform
|
336
|
+
import uuid
|
337
|
+
|
338
|
+
hostname = platform.node().replace('.', '-')[:20]
|
339
|
+
device_id = "{}-{}".format(hostname, str(uuid.uuid4())[:8])
|
340
|
+
|
341
|
+
print("Device ID: {}".format(device_id))
|
342
|
+
|
343
|
+
tunnel = PersistentTunnel(device_id=device_id)
|
344
|
+
tunnel.run()
|
345
|
+
|
346
|
+
|
347
|
+
if __name__ == "__main__":
|
348
|
+
main()
|
unitlab/simple_tunnel.py
CHANGED
@@ -61,13 +61,60 @@ class SimpleTunnel:
|
|
61
61
|
print("✅ Jupyter started on port {}".format(port))
|
62
62
|
return True
|
63
63
|
|
64
|
+
def get_cloudflared_path(self):
|
65
|
+
"""Get cloudflared binary, download if needed"""
|
66
|
+
import os
|
67
|
+
import platform
|
68
|
+
|
69
|
+
# Check if cloudflared exists in system
|
70
|
+
try:
|
71
|
+
import shutil
|
72
|
+
if shutil.which("cloudflared"):
|
73
|
+
print("✅ Using system cloudflared")
|
74
|
+
return "cloudflared"
|
75
|
+
except:
|
76
|
+
pass
|
77
|
+
|
78
|
+
# Check local binary
|
79
|
+
local_bin = os.path.expanduser("~/.local/bin/cloudflared")
|
80
|
+
if os.path.exists(local_bin):
|
81
|
+
print("✅ Using existing cloudflared from ~/.local/bin")
|
82
|
+
return local_bin
|
83
|
+
|
84
|
+
# Download it
|
85
|
+
print("📦 Downloading cloudflared (this may take a moment)...")
|
86
|
+
system = platform.system().lower()
|
87
|
+
if system == "linux":
|
88
|
+
arch = "amd64" if "x86" in platform.machine() else "arm64"
|
89
|
+
url = "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-{}".format(arch)
|
90
|
+
|
91
|
+
os.makedirs(os.path.expanduser("~/.local/bin"), exist_ok=True)
|
92
|
+
result = subprocess.run("curl -L {} -o {}".format(url, local_bin), shell=True, capture_output=True)
|
93
|
+
if result.returncode == 0:
|
94
|
+
subprocess.run("chmod +x {}".format(local_bin), shell=True)
|
95
|
+
print("✅ cloudflared downloaded successfully")
|
96
|
+
return local_bin
|
97
|
+
else:
|
98
|
+
print("❌ Failed to download cloudflared")
|
99
|
+
raise Exception("Could not download cloudflared")
|
100
|
+
|
101
|
+
raise Exception("Could not find or download cloudflared")
|
102
|
+
|
64
103
|
def start_tunnel(self, local_port=8888):
|
65
104
|
"""Start cloudflared tunnel - simple and direct"""
|
66
105
|
print("🔧 Starting Cloudflare tunnel...")
|
67
106
|
|
107
|
+
# Get cloudflared (downloads if needed)
|
108
|
+
try:
|
109
|
+
cloudflared = self.get_cloudflared_path()
|
110
|
+
except Exception as e:
|
111
|
+
print("⚠️ Error getting cloudflared: {}".format(e))
|
112
|
+
# Fallback - try to use system cloudflared anyway
|
113
|
+
cloudflared = "cloudflared"
|
114
|
+
|
68
115
|
# Simple command - just run the tunnel
|
69
116
|
cmd = [
|
70
|
-
|
117
|
+
cloudflared,
|
71
118
|
"tunnel",
|
72
119
|
"run",
|
73
120
|
"--url", "http://127.0.0.1:{}".format(local_port),
|
@@ -0,0 +1,23 @@
|
|
1
|
+
unitlab/__init__.py,sha256=Wtk5kQ_MTlxtd3mxJIn2qHVK5URrVcasMMPjD3BtrVM,214
|
2
|
+
unitlab/__main__.py,sha256=6Hs2PV7EYc5Tid4g4OtcLXhqVHiNYTGzSBdoOnW2HXA,29
|
3
|
+
unitlab/api_tunnel.py,sha256=SzDKFmxUg713KTkysc8qUnSmkfRc_dS3Cqrw2ONjn8I,8259
|
4
|
+
unitlab/auto_tunnel.py,sha256=Q4YyxrKOvM6jB1lQZd-QcHwt5SuMa60MpKWKEWF4fhY,5495
|
5
|
+
unitlab/binary_manager.py,sha256=Q1v2Odm0hk_3g7jfDUJQfkjEbUbSjtuyo2JDUyWjDrk,5468
|
6
|
+
unitlab/client.py,sha256=roVX8yq1x8LW1XEFuic4G-Cq1QEjsk2CySGkiJbxA78,25759
|
7
|
+
unitlab/cloudflare_api_tunnel.py,sha256=XgDOQ-ISNDAJOlbKp96inGix3An_eBnAQ2pORcGBM40,14061
|
8
|
+
unitlab/cloudflare_api_tunnel_backup.py,sha256=dG5Vax0JqrF2i-zxAFB-kNGyVSFR01-ovalwuJELqpo,28489
|
9
|
+
unitlab/dynamic_tunnel.py,sha256=fHPMouaY2q1N7e4jyre34ZeWk2mx7MKanoPfRnLNmc8,8980
|
10
|
+
unitlab/easy_tunnel.py,sha256=yfTGv7i9wtqMpMagpIrIQTrd3jknYwQ6IUgFGbcitKM,6735
|
11
|
+
unitlab/exceptions.py,sha256=68Tr6LreEzjQ3Vns8HAaWdtewtkNUJOvPazbf6NSnXU,950
|
12
|
+
unitlab/main.py,sha256=7gPZ_2n90sxDnq9oGZVKOkuifr-k7w2Tq3ZIldAUE8I,5877
|
13
|
+
unitlab/persistent_tunnel.py,sha256=0ubhsUOJUpDKG0xo18e6mN1V4pxNQvNFjylC1J1QglA,11712
|
14
|
+
unitlab/simple_tunnel.py,sha256=vWgVYFEbPoGCHmumujNrfBnDPuUCZgQJkVO3IvdygQA,6812
|
15
|
+
unitlab/tunnel_config.py,sha256=7CiAqasfg26YQfJYXapCBQPSoqw4jIx6yR64saybLLo,8312
|
16
|
+
unitlab/tunnel_service_token.py,sha256=ji96a4s4W2cFJrHZle0zBD85Ac_T862-gCKzBUomrxM,3125
|
17
|
+
unitlab/utils.py,sha256=83ekAxxfXecFTg76Z62BGDybC_skKJHYoLyawCD9wGM,1920
|
18
|
+
unitlab-2.3.29.dist-info/LICENSE.md,sha256=Gn7RRvByorAcAaM-WbyUpsgi5ED1-bKFFshbWfYYz2Y,1069
|
19
|
+
unitlab-2.3.29.dist-info/METADATA,sha256=OG1XzALj4PXPvmcrJ4l15-DXdelWtgxm5y0Wo9k9uZ8,844
|
20
|
+
unitlab-2.3.29.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
21
|
+
unitlab-2.3.29.dist-info/entry_points.txt,sha256=ig-PjKEqSCj3UTdyANgEi4tsAU84DyXdaOJ02NHX4bY,45
|
22
|
+
unitlab-2.3.29.dist-info/top_level.txt,sha256=Al4ZlTYE3fTJK2o6YLCDMH5_DjuQkffRBMxgmWbKaqQ,8
|
23
|
+
unitlab-2.3.29.dist-info/RECORD,,
|
unitlab-2.3.27.dist-info/RECORD
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
unitlab/__init__.py,sha256=Wtk5kQ_MTlxtd3mxJIn2qHVK5URrVcasMMPjD3BtrVM,214
|
2
|
-
unitlab/__main__.py,sha256=6Hs2PV7EYc5Tid4g4OtcLXhqVHiNYTGzSBdoOnW2HXA,29
|
3
|
-
unitlab/binary_manager.py,sha256=Q1v2Odm0hk_3g7jfDUJQfkjEbUbSjtuyo2JDUyWjDrk,5468
|
4
|
-
unitlab/client.py,sha256=TAv9ePzs8gGAgqGXkiGCxD-cI5dEGKWnyGKAU6UiR0M,24635
|
5
|
-
unitlab/cloudflare_api_tunnel.py,sha256=XgDOQ-ISNDAJOlbKp96inGix3An_eBnAQ2pORcGBM40,14061
|
6
|
-
unitlab/cloudflare_api_tunnel_backup.py,sha256=dG5Vax0JqrF2i-zxAFB-kNGyVSFR01-ovalwuJELqpo,28489
|
7
|
-
unitlab/exceptions.py,sha256=68Tr6LreEzjQ3Vns8HAaWdtewtkNUJOvPazbf6NSnXU,950
|
8
|
-
unitlab/main.py,sha256=7gPZ_2n90sxDnq9oGZVKOkuifr-k7w2Tq3ZIldAUE8I,5877
|
9
|
-
unitlab/simple_tunnel.py,sha256=vA6OP2ogvDlRxXlu52acNcdgZYNMI2G-m2V7bv2kyrY,4867
|
10
|
-
unitlab/tunnel_config.py,sha256=7CiAqasfg26YQfJYXapCBQPSoqw4jIx6yR64saybLLo,8312
|
11
|
-
unitlab/tunnel_service_token.py,sha256=ji96a4s4W2cFJrHZle0zBD85Ac_T862-gCKzBUomrxM,3125
|
12
|
-
unitlab/utils.py,sha256=83ekAxxfXecFTg76Z62BGDybC_skKJHYoLyawCD9wGM,1920
|
13
|
-
unitlab-2.3.27.dist-info/LICENSE.md,sha256=Gn7RRvByorAcAaM-WbyUpsgi5ED1-bKFFshbWfYYz2Y,1069
|
14
|
-
unitlab-2.3.27.dist-info/METADATA,sha256=A7IdVROWEy8jsfuER5nXt83nMOw-W8X7ZSgLeQyCHy0,844
|
15
|
-
unitlab-2.3.27.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
16
|
-
unitlab-2.3.27.dist-info/entry_points.txt,sha256=ig-PjKEqSCj3UTdyANgEi4tsAU84DyXdaOJ02NHX4bY,45
|
17
|
-
unitlab-2.3.27.dist-info/top_level.txt,sha256=Al4ZlTYE3fTJK2o6YLCDMH5_DjuQkffRBMxgmWbKaqQ,8
|
18
|
-
unitlab-2.3.27.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|