vssh 3.7.3__tar.gz → 3.7.4__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.4
2
2
  Name: vssh
3
- Version: 3.7.3
3
+ Version: 3.7.4
4
4
  Summary: Secure SSH/SCP tool with Tailscale failover, P2P transport, and MCP server
5
5
  Author-email: MeshPOP <mpop@mpop.dev>
6
6
  License: MIT
@@ -157,7 +157,7 @@ vssh history 20 web1 # Last 20 commands for specific host
157
157
 
158
158
  **Example `vssh status` output:**
159
159
  ```
160
- vssh v3.7.2 - Connection Status
160
+ vssh v3.7.4 - Connection Status
161
161
  ======================================================================
162
162
  c1 10.99.248.51 ● online (12ms)
163
163
  c2 10.99.14.187 ● online (11ms)
@@ -168,7 +168,7 @@ Total: 3/3 online
168
168
 
169
169
  **Example `vssh status --full` output:**
170
170
  ```
171
- vssh v3.7.2 - Cluster Status (full)
171
+ vssh v3.7.4 - Cluster Status (full)
172
172
  ======================================================================
173
173
  web1 10.99.1.10 ● online (8ms)
174
174
  disk: 45% used (120GB / 250GB) mem: 4.2GB / 16GB load: 0.42
@@ -213,7 +213,6 @@ vssh get --retry=3 <host>:<remote> <local> # Download with retry
213
213
  vssh sync <local_dir> <host>:<remote_dir> # Directory sync (8 parallel streams)
214
214
  vssh mput <host>:<base_path> <file1> <file2> ... # Multi-file single connection
215
215
  vssh fast <local> <host>:<remote> # Auto-select best method
216
- vssh p2p <local> <host>:<remote> # P2P direct (NAT hole-punch)
217
216
  vssh rsync <local> <host>:<remote> # Delta sync (only changed blocks)
218
217
  ```
219
218
 
@@ -234,7 +233,6 @@ vssh get web1:/var/log/app.log ./app.log # Download
234
233
  vssh sync ./config/ web1:/etc/app/ # Sync directory
235
234
  vssh mput web1:/backup/ file1.txt file2.txt file3.log # Multi-file
236
235
  vssh rsync ./src/ web1:/opt/src/ # Delta sync (only changes)
237
- vssh p2p ./dataset.tar.gz web2:/data/ # P2P bypass VPN relay
238
236
  ```
239
237
 
240
238
  vssh auto-compresses text files (`.py`, `.js`, `.json`, `.log`, `.md`, etc.) and skips upload for files with matching MD5.
@@ -623,16 +621,6 @@ Used internally for LAN-direct optimization.
623
621
 
624
622
  ---
625
623
 
626
- #### `p2p_signal` — P2P Signaling
627
-
628
- Used internally by `vssh p2p` to coordinate NAT hole-punch. Exchanges external IP/port info between peers via the VPN mesh relay.
629
-
630
- ```bash
631
- vssh rpc relay p2p_signal '{"external_ip":"203.0.113.1","external_port":48300,"local_port":48300}'
632
- ```
633
-
634
- ---
635
-
636
624
  ### RPC via Session
637
625
 
638
626
  You can run multiple RPC calls on a single persistent connection using `vssh session`:
@@ -899,22 +887,6 @@ Test upload and download speed to a server.
899
887
 
900
888
  ---
901
889
 
902
- #### `vssh_p2p_status` — P2P Status
903
-
904
- Check NAT hole-punch capability.
905
-
906
- ```json
907
- // Output:
908
- {
909
- "p2p_available": true,
910
- "external_ip": "203.0.113.1",
911
- "external_port": 48310,
912
- "nat_type": "cone"
913
- }
914
- ```
915
-
916
- ---
917
-
918
890
  #### `vssh_tunnel` — SSH Tunnel (Port Forwarding)
919
891
 
920
892
  Create an SSH tunnel to access a remote service locally.
@@ -134,7 +134,7 @@ vssh history 20 web1 # Last 20 commands for specific host
134
134
 
135
135
  **Example `vssh status` output:**
136
136
  ```
137
- vssh v3.7.2 - Connection Status
137
+ vssh v3.7.4 - Connection Status
138
138
  ======================================================================
139
139
  c1 10.99.248.51 ● online (12ms)
140
140
  c2 10.99.14.187 ● online (11ms)
@@ -145,7 +145,7 @@ Total: 3/3 online
145
145
 
146
146
  **Example `vssh status --full` output:**
147
147
  ```
148
- vssh v3.7.2 - Cluster Status (full)
148
+ vssh v3.7.4 - Cluster Status (full)
149
149
  ======================================================================
150
150
  web1 10.99.1.10 ● online (8ms)
151
151
  disk: 45% used (120GB / 250GB) mem: 4.2GB / 16GB load: 0.42
@@ -190,7 +190,6 @@ vssh get --retry=3 <host>:<remote> <local> # Download with retry
190
190
  vssh sync <local_dir> <host>:<remote_dir> # Directory sync (8 parallel streams)
191
191
  vssh mput <host>:<base_path> <file1> <file2> ... # Multi-file single connection
192
192
  vssh fast <local> <host>:<remote> # Auto-select best method
193
- vssh p2p <local> <host>:<remote> # P2P direct (NAT hole-punch)
194
193
  vssh rsync <local> <host>:<remote> # Delta sync (only changed blocks)
195
194
  ```
196
195
 
@@ -211,7 +210,6 @@ vssh get web1:/var/log/app.log ./app.log # Download
211
210
  vssh sync ./config/ web1:/etc/app/ # Sync directory
212
211
  vssh mput web1:/backup/ file1.txt file2.txt file3.log # Multi-file
213
212
  vssh rsync ./src/ web1:/opt/src/ # Delta sync (only changes)
214
- vssh p2p ./dataset.tar.gz web2:/data/ # P2P bypass VPN relay
215
213
  ```
216
214
 
217
215
  vssh auto-compresses text files (`.py`, `.js`, `.json`, `.log`, `.md`, etc.) and skips upload for files with matching MD5.
@@ -600,16 +598,6 @@ Used internally for LAN-direct optimization.
600
598
 
601
599
  ---
602
600
 
603
- #### `p2p_signal` — P2P Signaling
604
-
605
- Used internally by `vssh p2p` to coordinate NAT hole-punch. Exchanges external IP/port info between peers via the VPN mesh relay.
606
-
607
- ```bash
608
- vssh rpc relay p2p_signal '{"external_ip":"203.0.113.1","external_port":48300,"local_port":48300}'
609
- ```
610
-
611
- ---
612
-
613
601
  ### RPC via Session
614
602
 
615
603
  You can run multiple RPC calls on a single persistent connection using `vssh session`:
@@ -876,22 +864,6 @@ Test upload and download speed to a server.
876
864
 
877
865
  ---
878
866
 
879
- #### `vssh_p2p_status` — P2P Status
880
-
881
- Check NAT hole-punch capability.
882
-
883
- ```json
884
- // Output:
885
- {
886
- "p2p_available": true,
887
- "external_ip": "203.0.113.1",
888
- "external_port": 48310,
889
- "nat_type": "cone"
890
- }
891
- ```
892
-
893
- ---
894
-
895
867
  #### `vssh_tunnel` — SSH Tunnel (Port Forwarding)
896
868
 
897
869
  Create an SSH tunnel to access a remote service locally.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vssh"
7
- version = "3.7.3"
7
+ version = "3.7.4"
8
8
  description = "Secure SSH/SCP tool with Tailscale failover, P2P transport, and MCP server"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -38,4 +38,4 @@ Repository = "https://github.com/meshpop/vssh"
38
38
  vssh = "vssh_mcp_server"
39
39
 
40
40
  [tool.setuptools]
41
- py-modules = ["vssh", "vssh_p2p", "vssh_mcp_server"]
41
+ py-modules = ["vssh", "vssh_mcp_server"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vssh
3
- Version: 3.7.3
3
+ Version: 3.7.4
4
4
  Summary: Secure SSH/SCP tool with Tailscale failover, P2P transport, and MCP server
5
5
  Author-email: MeshPOP <mpop@mpop.dev>
6
6
  License: MIT
@@ -157,7 +157,7 @@ vssh history 20 web1 # Last 20 commands for specific host
157
157
 
158
158
  **Example `vssh status` output:**
159
159
  ```
160
- vssh v3.7.2 - Connection Status
160
+ vssh v3.7.4 - Connection Status
161
161
  ======================================================================
162
162
  c1 10.99.248.51 ● online (12ms)
163
163
  c2 10.99.14.187 ● online (11ms)
@@ -168,7 +168,7 @@ Total: 3/3 online
168
168
 
169
169
  **Example `vssh status --full` output:**
170
170
  ```
171
- vssh v3.7.2 - Cluster Status (full)
171
+ vssh v3.7.4 - Cluster Status (full)
172
172
  ======================================================================
173
173
  web1 10.99.1.10 ● online (8ms)
174
174
  disk: 45% used (120GB / 250GB) mem: 4.2GB / 16GB load: 0.42
@@ -213,7 +213,6 @@ vssh get --retry=3 <host>:<remote> <local> # Download with retry
213
213
  vssh sync <local_dir> <host>:<remote_dir> # Directory sync (8 parallel streams)
214
214
  vssh mput <host>:<base_path> <file1> <file2> ... # Multi-file single connection
215
215
  vssh fast <local> <host>:<remote> # Auto-select best method
216
- vssh p2p <local> <host>:<remote> # P2P direct (NAT hole-punch)
217
216
  vssh rsync <local> <host>:<remote> # Delta sync (only changed blocks)
218
217
  ```
219
218
 
@@ -234,7 +233,6 @@ vssh get web1:/var/log/app.log ./app.log # Download
234
233
  vssh sync ./config/ web1:/etc/app/ # Sync directory
235
234
  vssh mput web1:/backup/ file1.txt file2.txt file3.log # Multi-file
236
235
  vssh rsync ./src/ web1:/opt/src/ # Delta sync (only changes)
237
- vssh p2p ./dataset.tar.gz web2:/data/ # P2P bypass VPN relay
238
236
  ```
239
237
 
240
238
  vssh auto-compresses text files (`.py`, `.js`, `.json`, `.log`, `.md`, etc.) and skips upload for files with matching MD5.
@@ -623,16 +621,6 @@ Used internally for LAN-direct optimization.
623
621
 
624
622
  ---
625
623
 
626
- #### `p2p_signal` — P2P Signaling
627
-
628
- Used internally by `vssh p2p` to coordinate NAT hole-punch. Exchanges external IP/port info between peers via the VPN mesh relay.
629
-
630
- ```bash
631
- vssh rpc relay p2p_signal '{"external_ip":"203.0.113.1","external_port":48300,"local_port":48300}'
632
- ```
633
-
634
- ---
635
-
636
624
  ### RPC via Session
637
625
 
638
626
  You can run multiple RPC calls on a single persistent connection using `vssh session`:
@@ -899,22 +887,6 @@ Test upload and download speed to a server.
899
887
 
900
888
  ---
901
889
 
902
- #### `vssh_p2p_status` — P2P Status
903
-
904
- Check NAT hole-punch capability.
905
-
906
- ```json
907
- // Output:
908
- {
909
- "p2p_available": true,
910
- "external_ip": "203.0.113.1",
911
- "external_port": 48310,
912
- "nat_type": "cone"
913
- }
914
- ```
915
-
916
- ---
917
-
918
890
  #### `vssh_tunnel` — SSH Tunnel (Port Forwarding)
919
891
 
920
892
  Create an SSH tunnel to access a remote service locally.
@@ -3,7 +3,6 @@ README.md
3
3
  pyproject.toml
4
4
  vssh.py
5
5
  vssh_mcp_server.py
6
- vssh_p2p.py
7
6
  vssh.egg-info/PKG-INFO
8
7
  vssh.egg-info/SOURCES.txt
9
8
  vssh.egg-info/dependency_links.txt
@@ -1,3 +1,2 @@
1
1
  vssh
2
2
  vssh_mcp_server
3
- vssh_p2p
@@ -1009,67 +1009,6 @@ def _rpc_get_network_info(payload: dict) -> dict:
1009
1009
  'public_ip': get_cached_public_ip(),
1010
1010
  }
1011
1011
 
1012
- # P2P signaling storage (in-memory, temporary)
1013
- _p2p_signals = {} # {peer_ip: {external_ip, external_port, local_port, timestamp}}
1014
- _P2P_SIGNAL_TTL = 60 # 60 seconds
1015
-
1016
- @rpc_method('p2p_signal', 'read')
1017
- def _rpc_p2p_signal(payload: dict) -> dict:
1018
- """Exchange P2P signaling info for hole punching
1019
-
1020
- Payload: {external_ip, external_port, local_port, peer_vpn_ip (optional)}
1021
- Returns: Peer's info if available, or stores sender's info
1022
- """
1023
- import time
1024
-
1025
- sender_ip = payload.get('_sender_ip', 'unknown')
1026
- ext_ip = payload.get('external_ip')
1027
- ext_port = payload.get('external_port')
1028
- local_port = payload.get('local_port')
1029
- peer_vpn_ip = payload.get('peer_vpn_ip')
1030
-
1031
- if not all([ext_ip, ext_port, local_port]):
1032
- return {'error': 'external_ip, external_port, local_port required'}
1033
-
1034
- now = time.time()
1035
-
1036
- # Clean old signals
1037
- expired = [k for k, v in _p2p_signals.items() if now - v.get('timestamp', 0) > _P2P_SIGNAL_TTL]
1038
- for k in expired:
1039
- del _p2p_signals[k]
1040
-
1041
- # Store sender's info
1042
- _p2p_signals[sender_ip] = {
1043
- 'external_ip': ext_ip,
1044
- 'external_port': ext_port,
1045
- 'local_port': local_port,
1046
- 'timestamp': now
1047
- }
1048
-
1049
- # If peer_vpn_ip specified, return their info if available
1050
- if peer_vpn_ip and peer_vpn_ip in _p2p_signals:
1051
- peer_info = _p2p_signals[peer_vpn_ip]
1052
- return {
1053
- 'status': 'peer_found',
1054
- 'external_ip': peer_info['external_ip'],
1055
- 'external_port': peer_info['external_port'],
1056
- 'local_port': peer_info['local_port']
1057
- }
1058
-
1059
- return {'status': 'registered', 'waiting_for_peer': True}
1060
-
1061
- @rpc_method('p2p_get_peer', 'read')
1062
- def _rpc_p2p_get_peer(payload: dict) -> dict:
1063
- """Get peer's P2P signal info"""
1064
- peer_vpn_ip = payload.get('peer_vpn_ip')
1065
- if not peer_vpn_ip:
1066
- return {'error': 'peer_vpn_ip required'}
1067
-
1068
- if peer_vpn_ip in _p2p_signals:
1069
- return _p2p_signals[peer_vpn_ip]
1070
-
1071
- return {'error': 'peer not found'}
1072
-
1073
1012
  @rpc_method('restart_service', 'admin')
1074
1013
  def _rpc_restart_service(payload: dict) -> dict:
1075
1014
  """Restart a systemd service (admin only)"""
@@ -1618,43 +1557,6 @@ def put_fast(local: str, remote: str, lan: bool = True) -> bool:
1618
1557
  return _put_file(path, host, rpath)
1619
1558
 
1620
1559
 
1621
- # ========== P2P Transfer (NAT Hole-Punch) ==========
1622
- def put_p2p(local: str, remote: str, fallback: bool = True) -> bool:
1623
- """Upload via P2P hole-punching (bypasses VPN relay)
1624
-
1625
- Attempts P2P direct transfer for higher speed between NAT'd hosts.
1626
- Falls back to regular VPN transfer if P2P fails.
1627
-
1628
- Best for: Large files between NAT'd machines (e.g., local <-> remote)
1629
- Speed: ~11MB/s P2P vs ~10MB/s VPN relay
1630
- """
1631
- try:
1632
- from vssh_p2p import p2p_transfer_tcp
1633
- except ImportError:
1634
- print('[P2P] vssh_p2p module not found, using VPN')
1635
- return put_fast(local, remote)
1636
-
1637
- path = Path(local)
1638
- if not path.is_file():
1639
- print(f'Not a file: {local}')
1640
- return False
1641
-
1642
- host, rpath = remote.split(':', 1)
1643
-
1644
- # Try P2P first
1645
- print(f'[P2P] Attempting direct transfer to {host}...')
1646
- success = p2p_transfer_tcp(str(path), host, rpath)
1647
-
1648
- if success:
1649
- return True
1650
-
1651
- if fallback:
1652
- print('[P2P] Falling back to VPN relay...')
1653
- return put_fast(local, remote)
1654
-
1655
- return False
1656
-
1657
-
1658
1560
  # ========== Multi-connection Large File Transfer ==========
1659
1561
  def put_large_file(path: Path, host: str, rpath: str) -> bool:
1660
1562
  """Large file multi-connection upload"""
@@ -3653,7 +3555,6 @@ File transfer:
3653
3555
  sync <local_dir> <host>:<remote> Directory sync (8 parallel streams)
3654
3556
  mput <host>:<base> file1 file2 Multi-file upload (single connection)
3655
3557
  fast <local> <host>:<remote> Auto-select best transfer method
3656
- p2p <local> <host>:<remote> P2P direct (NAT hole-punch)
3657
3558
  rsync <local> <host>:<remote> Delta sync (only changed blocks)
3658
3559
 
3659
3560
  Pipes:
@@ -3709,14 +3610,6 @@ Env: VSSH_SECRET
3709
3610
  no_lan = '--no-lan' in args
3710
3611
  fast_args = [a for a in args[1:] if not a.startswith('-')]
3711
3612
  sys.exit(0 if put_fast(fast_args[0], fast_args[1], lan=not no_lan) else 1)
3712
- elif cmd == 'p2p':
3713
- # P2P direct transfer (NAT hole-punch, bypasses VPN relay)
3714
- no_fallback = '--no-fallback' in args
3715
- p2p_args = [a for a in args[1:] if not a.startswith('-')]
3716
- if len(p2p_args) < 2:
3717
- print('Usage: vssh p2p <local> <host>:<remote> [--no-fallback]')
3718
- sys.exit(1)
3719
- sys.exit(0 if put_p2p(p2p_args[0], p2p_args[1], fallback=not no_fallback) else 1)
3720
3613
  elif cmd == 'rsync':
3721
3614
  # Delta sync (only changed blocks)
3722
3615
  no_lan = '--no-lan' in args
@@ -8,8 +8,9 @@ Tools:
8
8
  - vssh_put: Upload file to server
9
9
  - vssh_get: Download file from server
10
10
  - vssh_sync: Sync directory between servers
11
- - vssh_p2p_status: P2P connection status
12
11
  - vssh_speed_test: Test transfer speed
12
+ - vssh_tunnel: SSH port forwarding tunnel
13
+ - vssh_keys: Manage vssh keys and secrets
13
14
 
14
15
  Run: python3 vssh-mcp-server.py
15
16
  """
@@ -467,24 +468,6 @@ def tool_vssh_speed_test(server: str, size_mb: int = 10):
467
468
  "latency_ms": round((upload_time + download_time) * 500 / size_mb, 1)
468
469
  }
469
470
 
470
- def tool_vssh_p2p_status():
471
- """Check P2P connection capabilities"""
472
- # Check if P2P module is available
473
- try:
474
- from vssh_p2p import stun_get_external
475
- external = stun_get_external()
476
- return {
477
- "p2p_available": True,
478
- "external_ip": external[0] if external else "unknown",
479
- "external_port": external[1] if external else 0,
480
- "nat_type": "cone" if external else "unknown"
481
- }
482
- except Exception as e:
483
- return {
484
- "p2p_available": False,
485
- "note": "P2P module not loaded"
486
- }
487
-
488
471
  def tool_vssh_tunnel(server: str, local_port: int, remote_port: int, remote_host: str = "localhost"):
489
472
  """Create SSH tunnel (port forwarding). Launches tunnel in background and returns PID."""
490
473
  servers = get_servers()
@@ -732,15 +715,6 @@ TOOLS = [
732
715
  "required": ["server"]
733
716
  }
734
717
  },
735
- {
736
- "name": "vssh_p2p_status",
737
- "description": "Check P2P (NAT hole-punch) connection capabilities for direct peer-to-peer transfers.",
738
- "inputSchema": {
739
- "type": "object",
740
- "properties": {},
741
- "required": []
742
- }
743
- },
744
718
  {
745
719
  "name": "vssh_tunnel",
746
720
  "description": "Create SSH tunnel (port forwarding) to access remote services locally. Launches tunnel in background, returns PID and access URL.",
@@ -822,8 +796,6 @@ def handle_request(request):
822
796
  result = tool_vssh_sync(args.get("source"), args.get("dest"), args.get("path"))
823
797
  elif tool_name == "vssh_speed_test":
824
798
  result = tool_vssh_speed_test(args.get("server"), args.get("size_mb", 10))
825
- elif tool_name == "vssh_p2p_status":
826
- result = tool_vssh_p2p_status()
827
799
  elif tool_name == "vssh_tunnel":
828
800
  result = tool_vssh_tunnel(
829
801
  args.get("server"),