Remove Python implementations of wssshc, wsssh, wsscp

- Delete wssshc.py, wsssh.py, wsscp.py files
- Update build.sh to remove pyinstaller commands and output messages
- Update Debian packaging to exclude Python script installations
- Update documentation to reflect C-only implementations
- Update CHANGELOG.md with version 1.4.5 entry
- Focus on C implementations for better performance and minimal dependencies
parent 250a9362
......@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.4.5] - 2025-09-16
### Removed
- **Python Implementations**: Removed Python implementations of wssshc, wsssh, and wsscp
- Deleted wssshc.py, wsssh.py, and wsscp.py files
- Removed pyinstaller commands from build.sh for these tools
- Updated Debian packaging to exclude Python script installations
- Cleaned up documentation and project structure references
- Maintained C implementations in wssshtools/ directory
### Changed
- **Build System**: Updated build.sh to only build C tools and wssshd daemon
- **Documentation**: Updated README.md, DOCUMENTATION.md, and project structure to reflect C-only implementations
- **Debian Packaging**: Modified wssshtools/debian/rules to only install wssshd.py and C tools
### Technical Details
- **C Implementation Focus**: Project now focuses exclusively on C implementations for better performance and minimal dependencies
- **Build Simplification**: Removed Python binary building from build process
- **Package Structure**: wsssh-tools package now contains only C tools and wssshd daemon
## [1.4.4] - 2025-09-15
### Added
......
......@@ -18,20 +18,17 @@ WebSocket SSH (wsssh) is a tunneling system that enables secure SSH/SCP access t
### Key Components
#### Python Implementation (Primary)
- **wssshd**: WebSocket SSH Daemon - Central server with web interface
- **wssshc**: WebSocket SSH Client - Registers machines with the daemon
- **wsssh**: SSH wrapper - Provides SSH access through tunnels
- **wsscp**: SCP wrapper - Provides SCP access through tunnels
#### Server Component
- **wssshd**: WebSocket SSH Daemon - Central server with web interface (Python)
#### C Implementation (Alternative)
#### C Implementation (Primary)
- **wssshc**: Lightweight C client for registration (OpenSSL-based)
- **wsssh**: Native SSH wrapper with direct system integration
- **wsscp**: Native SCP wrapper optimized for file transfers
### Core Features
- **Dual Implementation**: Python (full-featured) and C (lightweight) versions
- **C Implementation**: Lightweight and efficient C versions
- **Intelligent Hostname Parsing**: Automatic detection of client IDs and server endpoints
- **SSL/TLS Encryption**: Secure WebSocket communications with OpenSSL
- **Multi-client Support**: Route connections to different registered clients
......@@ -706,9 +703,6 @@ Key log messages to monitor:
```
wsssh/
├── wssshd.py # WebSocket SSH Daemon (Python)
├── wssshc.py # WebSocket SSH Client (Python)
├── wsssh.py # SSH wrapper (Python)
├── wsscp.py # SCP wrapper (Python)
├── build.sh # Build script (supports --debian, --server-only)
├── clean.sh # Clean script
├── requirements.txt # Python dependencies
......@@ -754,7 +748,7 @@ wsssh/
### Dependencies
#### Python Implementation
#### Server Dependencies (wssshd)
- **Python 3.7+**
- **websockets**: WebSocket client/server library
- **Flask**: Web framework for admin interface
......@@ -780,13 +774,13 @@ wsssh/
### Building from Source
#### Python Implementation
#### Server Build (wssshd)
```bash
# Install Python dependencies
pip3 install -r requirements.txt
# Build Python binaries
./build.sh
# Build server binary
./build.sh --server-only
# Build with Debian package
./build.sh --debian
......
......@@ -6,7 +6,7 @@ A modern SSH tunneling system that uses WebSocket connections to securely route
## Features
- **Dual Implementation**: Python (full-featured) and C (lightweight) versions available
- **C Implementation**: Lightweight and efficient C versions available
- **WebSocket-based Tunneling**: Secure SSH/SCP access through WebSocket connections
- **Client Registration**: Register client machines with the WebSocket daemon
- **Password Authentication**: Secure client registration with configurable passwords
......@@ -28,9 +28,9 @@ A modern SSH tunneling system that uses WebSocket connections to securely route
## Architecture
The system consists of multiple components available in both Python and C implementations:
The system consists of components implemented in C for optimal performance:
### Python Implementation (Primary)
### Server Component
1. **`wssshd`** - WebSocket SSH Daemon (server)
- Manages WebSocket connections with SSL/TLS encryption
- Handles client registrations with password authentication
......@@ -39,18 +39,19 @@ The system consists of multiple components available in both Python and C implem
- HTML5 terminal interface for SSH connections
- Donation modal integrated into the web interface
2. **`wssshc`** - WebSocket SSH Client (registration)
### C Implementation (Primary)
1. **`wssshc`** - WebSocket SSH Client (registration)
- Registers client machines with the daemon
- Maintains persistent WebSocket connection
- Automatic reconnection with configurable intervals
3. **`wsssh`** - SSH wrapper with tunneling
2. **`wsssh`** - SSH wrapper with tunneling
- Simplified CLI (no need to specify "ssh" command)
- Parses SSH commands and hostnames intelligently
- Establishes WebSocket tunnels automatically
- Launches SSH to local tunnel port
4. **`wsscp`** - SCP wrapper with tunneling
3. **`wsscp`** - SCP wrapper with tunneling
- Simplified CLI (no need to specify "scp" command)
- Similar to wsssh but optimized for SCP operations
- Handles file transfers through secure tunnels
......@@ -491,9 +492,6 @@ python3 -m pytest
```
wsssh/
├── wssshd.py # WebSocket SSH Daemon with web interface
├── wssshc.py # WebSocket SSH Client
├── wsssh.py # SSH wrapper (simplified CLI)
├── wsscp.py # SCP wrapper (simplified CLI)
├── build.sh # Build script (supports --debian flag)
├── clean.sh # Clean script
├── requirements.txt # Python dependencies
......
......@@ -136,17 +136,7 @@ if [ "$BUILD_DEBIAN_ONLY" = false ] && [ "$BUILD_WSSSHTOOLS_ONLY" = false ]; the
# Build client binaries
if [ "$BUILD_SERVER_ONLY" = false ]; then
# Build wssshc (client) binary
pyinstaller --onefile --distpath dist --runtime-tmpdir /tmp --clean wssshc.py
# Build wsssh and wsscp binaries unless --no-server is specified
if [ "$BUILD_NO_SERVER" = false ]; then
# Build wsssh binary
pyinstaller --onefile --distpath dist --runtime-tmpdir /tmp --clean wsssh.py
# Build wsscp binary
pyinstaller --onefile --distpath dist --runtime-tmpdir /tmp --clean wsscp.py
fi
fi
fi
......@@ -272,13 +262,6 @@ else
echo "- dist/wssshd (server with web interface)"
fi
if [ "$BUILD_SERVER_ONLY" = false ]; then
echo "- dist/wssshc (client)"
if [ "$BUILD_NO_SERVER" = false ]; then
echo "- dist/wsssh (SSH wrapper)"
echo "- dist/wsscp (SCP wrapper)"
fi
fi
if [ -d "wssshtools" ] && [ -f "wssshtools/wssshc" ]; then
if [ "$BUILD_NO_SERVER" = true ]; then
......
This diff is collapsed.
This diff is collapsed.
#!/usr/bin/env python3
"""
WebSocket SSH Client (wssshc)
Connects to wssshd server and registers as a client.
Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import argparse
import asyncio
import ssl
import websockets
import json
import socket
import configparser
import os
import signal
debug = False
# Active tunnels: request_id -> {'reader': tcp_reader, 'writer': tcp_writer}
active_tunnels = {}
async def forward_tcp_to_ws(tcp_reader, websocket, request_id):
try:
while True:
data = await tcp_reader.read(1024)
if not data:
break
if debug: print(f"[DEBUG] Sending tunnel_response, data len: {len(data)}, data: {data[:50].decode('utf-8', errors='replace') if data else 'empty'}, hex: {data.hex()[:100]}...")
await websocket.send(json.dumps({
"type": "tunnel_response",
"request_id": request_id,
"data": data.hex()
}))
except Exception as e:
if debug: print(f"[DEBUG] TCP to WS error: {e}")
finally:
# Cleanup tunnel
if request_id in active_tunnels:
del active_tunnels[request_id]
if debug: print(f"[DEBUG] Tunnel {request_id} closed")
async def connect_to_server(server_ip, port, client_id, password, interval, shutdown_event=None):
uri = f"wss://{server_ip}:{port}"
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
while True:
# Check for shutdown signal
if shutdown_event and shutdown_event.is_set():
if debug: print("[DEBUG] Shutdown signal received, exiting")
break
try:
async with websockets.connect(uri, ssl=ssl_context) as websocket:
# Register
await websocket.send(json.dumps({"type": "register", "id": client_id, "password": password}))
print(f"Connected and registered as {client_id}")
# Wait for registration acknowledgment
response = await websocket.recv()
data = json.loads(response)
if data.get('type') == 'registered':
print(f"Successfully registered as {client_id}")
elif data.get('type') == 'registration_error':
print(f"Registration failed: {data.get('error', 'Unknown error')}")
return # Exit and retry
async for message in websocket:
if debug: print(f"[DEBUG] WebSocket message: {message[:100]}...")
data = json.loads(message)
if data.get('type') == 'tunnel_request':
request_id = data['request_id']
if debug: print(f"[DEBUG] Tunnel request received: {request_id}")
try:
# Connect to local SSH server
tcp_reader, tcp_writer = await asyncio.open_connection('localhost', 22)
active_tunnels[request_id] = {'reader': tcp_reader, 'writer': tcp_writer}
# Start forwarding from TCP to WS
asyncio.create_task(forward_tcp_to_ws(tcp_reader, websocket, request_id))
if debug: print(f"[DEBUG] Connected to local SSH server for tunnel {request_id}")
except Exception as e:
if debug: print(f"[DEBUG] Tunnel setup error: {e}")
elif data.get('type') == 'tunnel_data':
request_id = data['request_id']
if request_id in active_tunnels:
# Forward data to local SSH
tunnel_data = bytes.fromhex(data['data'])
if debug: print(f"[DEBUG] Received tunnel_data, hex len: {len(data['data'])}, hex: {data['data'][:100]}..., decoded: {tunnel_data[:50].decode('utf-8', errors='replace') if tunnel_data else 'empty'}")
active_tunnels[request_id]['writer'].write(tunnel_data)
await active_tunnels[request_id]['writer'].drain()
elif data.get('type') == 'tunnel_close':
request_id = data['request_id']
if request_id in active_tunnels:
# Close tunnel
active_tunnels[request_id]['writer'].close()
await active_tunnels[request_id]['writer'].wait_closed()
del active_tunnels[request_id]
if debug: print(f"[DEBUG] Tunnel {request_id} closed")
except Exception as e:
print(f"Connection failed: {e}, retrying in {interval} seconds")
await asyncio.sleep(interval)
def load_config_file(config_path):
"""Load configuration from a specific file path"""
if not os.path.exists(config_path):
return {}
config = configparser.ConfigParser()
try:
config.read(config_path)
if 'wssshc' in config:
section = config['wssshc']
defaults = {}
for key in ['password', 'id']:
if key in section:
defaults[key] = section[key]
if 'server-ip' in section:
defaults['server_ip'] = section['server-ip']
elif 'domain' in section:
defaults['server_ip'] = section['domain']
if 'port' in section:
defaults['port'] = int(section['port'])
if 'interval' in section:
defaults['interval'] = int(section['interval'])
return defaults
except Exception as e:
if debug: print(f"[DEBUG] Error reading config file {config_path}: {e}")
return {}
def main():
# Configuration hierarchy:
# 1. System config (/etc/wssshc.conf)
# 2. User config (~/.config/wsssh/wssshc.conf)
# 3. Command line arguments (highest priority)
# Load system config first (lowest priority)
system_config = '/etc/wssshc.conf'
defaults = load_config_file(system_config)
# Load user config (medium priority, overrides system)
user_config = os.path.expanduser('~/.config/wsssh/wssshc.conf')
user_defaults = load_config_file(user_config)
defaults.update(user_defaults)
# Set default values if not set by config files
defaults.setdefault('interval', 30)
defaults.setdefault('port', 9898)
# Parse command line arguments (highest priority)
parser = argparse.ArgumentParser(description='WebSocket SSH Client (wssshc)')
parser.set_defaults(**defaults)
parser.add_argument('--config', help='Configuration file path (overrides default hierarchy)')
parser.add_argument('--server-ip', help='Server IP address')
parser.add_argument('--port', type=int, help='Server port')
parser.add_argument('--id', help='Client ID')
parser.add_argument('--password', help='Registration password')
parser.add_argument('--interval', type=int, help='Reconnect interval in seconds (default: 30)')
parser.add_argument('--debug', action='store_true', help='Enable debug output')
# Parse just the config argument first to check for custom config file
temp_parser = argparse.ArgumentParser(add_help=False)
temp_parser.add_argument('--config')
temp_args, remaining = temp_parser.parse_known_args()
# If --config is specified, load that file instead of the hierarchy
if temp_args.config:
custom_defaults = load_config_file(temp_args.config)
defaults.update(custom_defaults)
parser.set_defaults(**defaults)
args = parser.parse_args()
args = parser.parse_args()
# Check required arguments
if not args.server_ip:
parser.error('--server-ip is required')
if not args.id:
parser.error('--id is required')
if not args.password:
parser.error('--password is required')
global debug
debug = args.debug
# Set up signal handling for clean exit
shutdown_event = asyncio.Event()
def signal_handler(signum, frame):
if debug: print(f"[DEBUG] Received signal {signum}, initiating shutdown")
shutdown_event.set()
# Register signal handler for SIGINT (Ctrl+C)
signal.signal(signal.SIGINT, signal_handler)
asyncio.run(connect_to_server(args.server_ip, args.port, args.id, args.password, args.interval, shutdown_event))
if __name__ == '__main__':
main()
\ No newline at end of file
......@@ -52,10 +52,7 @@ override_dh_auto_install:
install -m 644 debian/wssshc.service debian/wsssh-tools/lib/systemd/system/
# Install Python scripts
install -m 755 ../wssshc.py debian/wsssh-tools/usr/bin/
install -m 755 ../wssshd.py debian/wsssh-tools/usr/bin/
install -m 755 ../wsssh.py debian/wsssh-tools/usr/bin/
install -m 755 ../wsscp.py debian/wsssh-tools/usr/bin/
override_dh_auto_clean:
make clean
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment