-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlauncher.py
More file actions
135 lines (109 loc) · 4.24 KB
/
launcher.py
File metadata and controls
135 lines (109 loc) · 4.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env python3
import os
import sys
import subprocess
import signal
import time
import socket
import re
import tempfile
import webbrowser
import urllib.request
import json
PROJ_DIR = os.path.dirname(os.path.abspath(__file__))
SERVER_FILE = os.path.join(PROJ_DIR, 'server.js')
NODE_PORT = 0
p_node = None
p_tunnel = None
temp_key_path = None
def get_free_port():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 0))
return s.getsockname()[1]
def cleanup(sig, frame):
print("\n[!] Shutting down...")
if p_node:
p_node.terminate()
if p_tunnel:
p_tunnel.terminate()
if temp_key_path and os.path.exists(temp_key_path):
try:
os.remove(temp_key_path)
os.remove(temp_key_path + ".pub")
except:
pass
sys.exit(0)
def main():
global p_node, p_tunnel, temp_key_path
signal.signal(signal.SIGINT, cleanup)
signal.signal(signal.SIGTERM, cleanup)
print("--- P2Ply Secure Launcher (Remote Only) ---")
if not os.path.exists(os.path.join(PROJ_DIR, 'node_modules')):
print("[*] Installing dependencies...")
subprocess.check_call(['npm', 'install'], cwd=PROJ_DIR)
remote_mode = True
env = os.environ.copy()
port = get_free_port()
env['PORT'] = str(port)
print(f"[*] Starting local server on port {port}...")
p_node = subprocess.Popen(['node', SERVER_FILE], cwd=PROJ_DIR, env=env)
time.sleep(1)
if p_node.poll() is not None:
print("[!] Node server failed to start.")
sys.exit(1)
if remote_mode:
print("[*] establishing secure tunnel...")
with tempfile.NamedTemporaryFile(delete=True, prefix='p2ply_key_') as tmp:
temp_key_path = tmp.name
subprocess.check_call(['ssh-keygen', '-t', 'ed25519', '-f', temp_key_path, '-N', '', '-q'])
cmd = [
'ssh', '-R', f'80:localhost:{port}',
'-i', temp_key_path,
'-o', 'StrictHostKeyChecking=no',
'-o', 'UserKnownHostsFile=/dev/null',
'-o', 'ServerAliveInterval=30',
'-o', 'ServerAliveCountMax=3',
'nokey@localhost.run'
]
p_tunnel = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
print("[*] Waiting for tunnel URL...")
try:
while True:
line = p_tunnel.stdout.readline()
if not line: break
match = re.search(r'(https://[a-zA-Z0-9-]+\.(localhost\.run|lhr\.life))', line)
if match:
url = match.group(1)
if 'admin.localhost.run' not in url and 'localhost.run/docs' not in url:
print(f"\n[+] REMOTE ACCESS URL: {url}")
print("[!] Share this URL ONLY with trusted peers.")
print("[*] Opening browser...")
try:
req = urllib.request.Request(
f"http://localhost:{port}/set-remote-url",
data=json.dumps({"url": url}).encode('utf-8'),
headers={'Content-Type': 'application/json'}
)
urllib.request.urlopen(req)
except Exception as e:
print(f"\n[!] Failed to sync URL with server: {e}")
webbrowser.open(url)
break
except Exception as e:
print(f"\n[!] Tunnel error: {e}")
print("\n[*] System active. Press Ctrl+C to stop.")
try:
while True:
time.sleep(2)
if p_node.poll() is not None:
print("\n[!] Local server stopped unexpectedly.")
break
if p_tunnel and p_tunnel.poll() is not None:
print("\n[!] Tunnel connection lost.")
print("[!] Poor connection or domain tunnel closed. Shutting down...")
break
except KeyboardInterrupt:
pass
cleanup(None, None)
if __name__ == '__main__':
main()