Major refactoring: Extract shared libraries and fix port option behavior

- Extracted ~1500+ lines of duplicate code into shared libraries:
  * wssshlib.h/.c - Shared utilities (config, flags, ports, IDs)
  * websocket.h/.c - WebSocket functions (handshake, framing, messaging)
  * wssh_ssl.h/.c - SSL/TLS setup functions
  * tunnel.h/.c - Tunnel management (setup, reconnection, data handling)

- Fixed critical port option behavior:
  * -p/-P options now correctly specify wssshd server port
  * Removed misleading documentation about options being passed through
  * Updated help text and man pages to reflect correct behavior

- Cleaned up help documentation:
  * Removed duplicate 'Options:' sections from wsssh and wsscp
  * Consolidated all options into single, clean sections

- Updated build system:
  * Modified configure.sh and Makefile for new library structure
  * Proper linking of wsssh and wsscp against shared libraries

- Updated documentation:
  * CHANGELOG.md - Added version 1.4.6 with comprehensive details
  * README.md - Updated architecture and project structure
  * DOCUMENTATION.md - Reflected new library structure
  * Man pages - Corrected port option examples
  * TODO.md - Updated completion status

- Maintained backward compatibility while improving maintainability
parent 34202ca9
......@@ -5,6 +5,41 @@ 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.6] - 2025-09-16
### Added
- **Code Refactoring and Library Architecture**: Major refactoring to eliminate code duplication
- Created shared libraries: `wssshlib.h/.c`, `websocket.h/.c`, `wssh_ssl.h/.c`, `tunnel.h/.c`
- Extracted ~1500+ lines of duplicate code between wsssh.c and wsscp.c
- Improved maintainability and code organization with modular architecture
- Enhanced build system with proper library dependencies
- **Port Option Behavior Correction**: Fixed critical port option behavior
- `-p`/`-P` options now correctly specify wssshd server port (not SSH/SCP server port)
- Removed misleading "passed through to ssh/scp" documentation
- Updated help text to clearly indicate port options are consumed by wsssh/wsscp
- Fixed argument parsing to properly handle wssshd server port specification
### Changed
- **C Implementation Architecture**: Refactored wsssh.c and wsscp.c to use shared libraries
- Both tools now link against common libraries for WebSocket, SSL, and tunnel management
- Reduced binary size and improved memory efficiency
- Enhanced code reusability and maintainability
- Consistent behavior between wsssh and wsscp implementations
- **Help Documentation**: Updated help output for both wsssh and wsscp
- Removed duplicate "Options:" sections
- Consolidated all options into single, clean "Options:" section
- Corrected port option descriptions to reflect actual behavior
- Improved user experience with clearer documentation
### Technical Details
- **Library Dependencies**: New build system properly links wsssh and wsscp against shared libraries
- **Code Deduplication**: Eliminated redundant implementations of WebSocket, SSL, and tunnel functions
- **Port Handling**: Fixed hostname parsing and port precedence logic
- **Build System**: Updated configure.sh and Makefile to handle new library structure
- **Backward Compatibility**: All existing functionality preserved, new features are additive
## [1.4.5] - 2025-09-16
### Removed
......
......@@ -714,6 +714,14 @@ wsssh/
│ ├── wssshc.c # C client (280 lines)
│ ├── wsssh.c # C SSH wrapper (378 lines)
│ ├── wsscp.c # C SCP wrapper (418 lines)
│ ├── wssshlib.h # Shared utilities library header
│ ├── wssshlib.c # Shared utilities library implementation
│ ├── websocket.h # WebSocket functions library header
│ ├── websocket.c # WebSocket functions library implementation
│ ├── wssh_ssl.h # SSL functions library header
│ ├── wssh_ssl.c # SSL functions library implementation
│ ├── tunnel.h # Tunnel management library header
│ ├── tunnel.c # Tunnel management library implementation
│ ├── configure.sh # Build configuration
│ ├── Makefile # GNU Make build system
│ └── debian/ # Debian packaging for wsssh-tools
......
......@@ -50,11 +50,13 @@ The system consists of components implemented in C for optimal performance:
- Parses SSH commands and hostnames intelligently
- Establishes WebSocket tunnels automatically
- Launches SSH to local tunnel port
- Uses shared libraries for WebSocket, SSL, and tunnel management
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
- Uses shared libraries for WebSocket, SSL, and tunnel management
### C Implementation (Alternative)
Located in the `wssshtools/` directory:
......@@ -232,9 +234,9 @@ Port is specified using `-p` (SSH) or `-P` (SCP) options, or from config file.
## Port Detection Priority
1. **Command line option**: `-p <port>` (SSH) or `-P <port>` (SCP)
2. **Config file**: `port` setting in `~/.config/wsssh/wsssh.conf`
3. **Default**: `22` (standard SSH port)
1. **Command line option**: `-p <port>` (SSH) or `-P <port>` (SCP) - specifies wssshd server port
2. **Config file**: `port` setting in `~/.config/wsssh/wsssh.conf` - wssshd server port
3. **Default**: `9898` (wssshd default port)
## Detailed Usage
......@@ -508,6 +510,14 @@ wsssh/
│ ├── wssshc.c # C client for registration
│ ├── wsssh.c # C SSH wrapper
│ ├── wsscp.c # C SCP wrapper
│ ├── wssshlib.h # Shared utilities library header
│ ├── wssshlib.c # Shared utilities library implementation
│ ├── websocket.h # WebSocket functions library header
│ ├── websocket.c # WebSocket functions library implementation
│ ├── wssh_ssl.h # SSL functions library header
│ ├── wssh_ssl.c # SSL functions library implementation
│ ├── tunnel.h # Tunnel management library header
│ ├── tunnel.c # Tunnel management library implementation
│ ├── configure.sh # C build configuration
│ ├── Makefile # C build system
│ └── debian/ # Debian packaging
......@@ -587,7 +597,51 @@ Your support helps us continue developing and maintaining this open-source proje
## Changelog
### Version 1.4.4 (Latest)
### Version 1.4.6 (Latest)
**Major Refactoring:**
- **Code Architecture Overhaul**: Major refactoring to eliminate code duplication
- Created shared libraries: `wssshlib.h/.c`, `websocket.h/.c`, `wssh_ssl.h/.c`, `tunnel.h/.c`
- Extracted ~1500+ lines of duplicate code between wsssh.c and wsscp.c
- Improved maintainability and code organization with modular architecture
- Enhanced build system with proper library dependencies
**Critical Bug Fixes:**
- **Port Option Behavior Correction**: Fixed critical port option behavior
- `-p`/`-P` options now correctly specify wssshd server port (not SSH/SCP server port)
- Removed misleading "passed through to ssh/scp" documentation
- Updated help text to clearly indicate port options are consumed by wsssh/wsscp
- Fixed argument parsing to properly handle wssshd server port specification
**User Experience Improvements:**
- **Help Documentation Cleanup**: Fixed duplicate "Options:" sections in help output
- Removed duplicate "Options:" sections from both wsssh and wsscp help
- Consolidated all options into single, clean "Options:" section
- Improved user experience with clearer documentation
**Technical Improvements:**
- **Library Dependencies**: New build system properly links wsssh and wsscp against shared libraries
- **Code Deduplication**: Eliminated redundant implementations of WebSocket, SSL, and tunnel functions
- **Port Handling**: Fixed hostname parsing and port precedence logic
- **Build System**: Updated configure.sh and Makefile to handle new library structure
- **Backward Compatibility**: All existing functionality preserved, new features are additive
### Version 1.4.5
**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
### Version 1.4.4
**New Features:**
- **Dynamic Terminal Sizing**: Web terminal automatically adjusts to browser window dimensions
......
# WebSocket SSH - Future Enhancements Roadmap
## Recently Completed (v1.4.6)
- [x] **Code Refactoring and Library Architecture**: Major refactoring to eliminate code duplication
- Created shared libraries: `wssshlib.h/.c`, `websocket.h/.c`, `wssh_ssl.h/.c`, `tunnel.h/.c`
- Extracted ~1500+ lines of duplicate code between wsssh.c and wsscp.c
- Improved maintainability and code organization with modular architecture
- Enhanced build system with proper library dependencies
- [x] **Port Option Behavior Correction**: Fixed critical port option behavior
- `-p`/`-P` options now correctly specify wssshd server port (not SSH/SCP server port)
- Removed misleading "passed through to ssh/scp" documentation
- Updated help text to clearly indicate port options are consumed by wsssh/wsscp
- Fixed argument parsing to properly handle wssshd server port specification
- [x] **Help Documentation Cleanup**: Fixed duplicate "Options:" sections in help output
- Removed duplicate "Options:" sections from both wsssh and wsscp help
- Consolidated all options into single, clean "Options:" section
- Improved user experience with clearer documentation
- [x] **Documentation Updates**: Updated CHANGELOG.md, README.md, DOCUMENTATION.md, and man pages for version 1.4.6
## Recently Completed (v1.4.5)
- [x] **Python Implementation Removal**: 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
- [x] **Build System**: Updated build.sh to only build C tools and wssshd daemon
- [x] **Documentation**: Updated README.md, DOCUMENTATION.md, and project structure to reflect C-only implementations
- [x] **Debian Packaging**: Modified wssshtools/debian/rules to only install wssshd.py and C tools
## Recently Completed (v1.4.4)
- [x] **Dynamic Terminal Sizing**: Implemented proper terminal dimension calculation and transmission
- [x] **Terminal Resize Support**: Added real-time terminal resizing when browser window changes
......
......@@ -25,6 +25,7 @@ BUILD_SERVER_ONLY=false
BUILD_NO_SERVER=false
BUILD_WSSSHTOOLS_ONLY=false
BUILD_PACKAGES=false
BUILD_CLEAN=false
while [[ $# -gt 0 ]]; do
case $1 in
--debian)
......@@ -54,6 +55,10 @@ while [[ $# -gt 0 ]]; do
BUILD_WSSSHTOOLS_ONLY=true
shift
;;
--clean)
BUILD_CLEAN=true
shift
;;
--help|-h)
echo "Usage: $0 [options]"
echo "Options:"
......@@ -63,12 +68,13 @@ while [[ $# -gt 0 ]]; do
echo " --server-only Build only the server (wssshd) and wsssh-server Debian package"
echo " --no-server Skip building the server (wssshd) and wsssh-server package"
echo " --wssshtools-only Build only the C tools (wssshtools) and wsssh-tools package"
echo " --clean Clean build artifacts (equivalent to ./clean.sh)"
echo " --help, -h Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
echo "Usage: $0 [--debian] [--debian-only] [--packages] [--server-only] [--no-server] [--wssshtools-only] [--help]"
echo "Usage: $0 [--debian] [--debian-only] [--packages] [--server-only] [--no-server] [--wssshtools-only] [--clean] [--help]"
echo "Try '$0 --help' for more information."
exit 1
;;
......@@ -76,6 +82,81 @@ while [[ $# -gt 0 ]]; do
done
# Handle clean option first
if [ "$BUILD_CLEAN" = true ]; then
echo "Cleaning build artifacts..."
# Remove PyInstaller build artifacts
rm -rf build/
rm -rf dist/
rm -f *.spec
rm -f wssshd # Remove PyInstaller binary
# Remove virtual environment
rm -rf venv/
# Remove SSL certificates
rm -f cert.pem key.pem
# Remove logos and icons
rm -rf logos/
# Remove C version build artifacts
if [ -d "wssshtools" ]; then
cd wssshtools
make clean 2>/dev/null || true
rm -f Makefile
rm -f configure.sh.stamp
rm -f man/*.1.gz 2>/dev/null || true
cd ..
fi
# Remove Debian packaging artifacts
# wsssh-server packages
rm -f dist/wsssh-server*.deb
rm -f dist/wsssh-server*.dsc
rm -f dist/wsssh-server*.tar.gz
rm -f dist/wsssh-server*.changes
rm -f dist/wsssh-server*.buildinfo
rm -f wsssh-server*.deb
rm -f wsssh-server*.dsc
rm -f wsssh-server*.tar.gz
rm -f wsssh-server*.changes
rm -f wsssh-server*.buildinfo
# wsssh-tools packages
rm -f dist/wsssh-tools*.deb
rm -f dist/wsssh-tools*.dsc
rm -f dist/wsssh-tools*.tar.gz
rm -f dist/wsssh-tools*.changes
rm -f dist/wsssh-tools*.buildinfo
rm -f wsssh-tools*.deb
rm -f wsssh-tools*.dsc
rm -f wsssh-tools*.tar.gz
rm -f wsssh-tools*.changes
rm -f wsssh-tools*.buildinfo
# Remove Debian build directory and artifacts
if [ -d "wsssh-server" ]; then
rm -rf wsssh-server/debian/wsssh-server/
rm -f wsssh-server/debian/files
rm -f wsssh-server/debian/*.debhelper*
rm -f wsssh-server/debian/*.substvars
rm -f wsssh-server/debian/debhelper-build-stamp
fi
if [ -d "wssshtools" ]; then
rm -rf wssshtools/debian/wsssh-tools/
rm -f wssshtools/debian/files
rm -f wssshtools/debian/*.debhelper*
rm -f wssshtools/debian/*.substvars
rm -f wssshtools/debian/debhelper-build-stamp
fi
echo "Clean complete. All build artifacts removed."
exit 0
fi
# Create dist directory if not exists
mkdir -p dist
......@@ -99,7 +180,7 @@ if [ "$BUILD_DEBIAN_ONLY" = false ] && [ "$BUILD_WSSSHTOOLS_ONLY" = false ]; the
# Generate SSL certificates if they don't exist
if [ ! -f "cert.pem" ] || [ ! -f "key.pem" ]; then
echo "Generating SSL certificates..."
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 36500 -nodes -subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
fi
# Generate logos and icons from image.jpg if it exists
......@@ -136,7 +217,8 @@ if [ "$BUILD_DEBIAN_ONLY" = false ] && [ "$BUILD_WSSSHTOOLS_ONLY" = false ]; the
# Build client binaries
if [ "$BUILD_SERVER_ONLY" = false ]; then
# Client binaries are not built in this version
echo "Client binaries not built in this version"
fi
fi
......
......@@ -18,65 +18,5 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# Remove PyInstaller build artifacts
rm -rf build/
rm -rf dist/
rm -f *.spec
# Remove C version build artifacts
if [ -d "wssshtools" ]; then
cd wssshtools
make clean 2>/dev/null || true
rm -f Makefile
rm -f configure.sh.stamp
rm -f man/*.1.gz 2>/dev/null || true
cd ..
fi
# Remove Debian packaging artifacts
# wsssh-server packages
rm -f dist/wsssh-server*.deb
rm -f dist/wsssh-server*.dsc
rm -f dist/wsssh-server*.tar.gz
rm -f dist/wsssh-server*.changes
rm -f dist/wsssh-server*.buildinfo
rm -f wsssh-server*.deb
rm -f wsssh-server*.dsc
rm -f wsssh-server*.tar.gz
rm -f wsssh-server*.changes
rm -f wsssh-server*.buildinfo
# wsssh-tools packages
rm -f dist/wsssh-tools*.deb
rm -f dist/wsssh-tools*.dsc
rm -f dist/wsssh-tools*.tar.gz
rm -f dist/wsssh-tools*.changes
rm -f dist/wsssh-tools*.buildinfo
rm -f wsssh-tools*.deb
rm -f wsssh-tools*.dsc
rm -f wsssh-tools*.tar.gz
rm -f wsssh-tools*.changes
rm -f wsssh-tools*.buildinfo
# Remove Debian build directory and artifacts
if [ -d "wsssh-server" ]; then
rm -rf wsssh-server/debian/wsssh-server/
rm -f wsssh-server/debian/files
rm -f wsssh-server/debian/*.debhelper*
rm -f wsssh-server/debian/*.substvars
rm -f wsssh-server/debian/debhelper-build-stamp
fi
if [ -d "wssshtools" ]; then
rm -rf wssshtools/debian/wsssh-tools/
rm -f wssshtools/debian/files
rm -f wssshtools/debian/*.debhelper*
rm -f wssshtools/debian/*.substvars
rm -f wssshtools/debian/debhelper-build-stamp
fi
# Optionally remove SSL certificates (uncomment if needed)
# rm -f cert.pem key.pem
echo "Clean complete. Build artifacts removed."
echo "Note: SSL certificates (cert.pem, key.pem) preserved. Uncomment lines in clean.sh to remove them."
\ No newline at end of file
# Use build.sh --clean for consistent cleaning
./build.sh --clean
\ No newline at end of file
logos/banner-800x200.png

52.7 KB | W: | H:

logos/banner-800x200.png

52.7 KB | W: | H:

logos/banner-800x200.png
logos/banner-800x200.png
logos/banner-800x200.png
logos/banner-800x200.png
  • 2-up
  • Swipe
  • Onion skin
logos/icon-128.png

23.2 KB | W: | H:

logos/icon-128.png

23.2 KB | W: | H:

logos/icon-128.png
logos/icon-128.png
logos/icon-128.png
logos/icon-128.png
  • 2-up
  • Swipe
  • Onion skin
logos/icon-16.png

2.34 KB | W: | H:

logos/icon-16.png

2.34 KB | W: | H:

logos/icon-16.png
logos/icon-16.png
logos/icon-16.png
logos/icon-16.png
  • 2-up
  • Swipe
  • Onion skin
logos/icon-256.png

84.6 KB | W: | H:

logos/icon-256.png

84.6 KB | W: | H:

logos/icon-256.png
logos/icon-256.png
logos/icon-256.png
logos/icon-256.png
  • 2-up
  • Swipe
  • Onion skin
logos/icon-32.png

3.24 KB | W: | H:

logos/icon-32.png

3.24 KB | W: | H:

logos/icon-32.png
logos/icon-32.png
logos/icon-32.png
logos/icon-32.png
  • 2-up
  • Swipe
  • Onion skin
logos/icon-48.png

4.91 KB | W: | H:

logos/icon-48.png

4.91 KB | W: | H:

logos/icon-48.png
logos/icon-48.png
logos/icon-48.png
logos/icon-48.png
  • 2-up
  • Swipe
  • Onion skin
logos/icon-64.png

7.23 KB | W: | H:

logos/icon-64.png

7.23 KB | W: | H:

logos/icon-64.png
logos/icon-64.png
logos/icon-64.png
logos/icon-64.png
  • 2-up
  • Swipe
  • Onion skin
logos/logo-128.png

23.2 KB | W: | H:

logos/logo-128.png

23.2 KB | W: | H:

logos/logo-128.png
logos/logo-128.png
logos/logo-128.png
logos/logo-128.png
  • 2-up
  • Swipe
  • Onion skin
logos/logo-256.png

84.6 KB | W: | H:

logos/logo-256.png

84.6 KB | W: | H:

logos/logo-256.png
logos/logo-256.png
logos/logo-256.png
logos/logo-256.png
  • 2-up
  • Swipe
  • Onion skin
logos/logo-512.png

307 KB | W: | H:

logos/logo-512.png

307 KB | W: | H:

logos/logo-512.png
logos/logo-512.png
logos/logo-512.png
logos/logo-512.png
  • 2-up
  • Swipe
  • Onion skin
logos/logo-64.png

7.23 KB | W: | H:

logos/logo-64.png

7.23 KB | W: | H:

logos/logo-64.png
logos/logo-64.png
logos/logo-64.png
logos/logo-64.png
  • 2-up
  • Swipe
  • Onion skin
wsssh-server (1.4.3-1) unstable; urgency=medium
wsssh-server (1.4.4-1) unstable; urgency=medium
* New upstream release 1.4.3
* Fixed Debian package dependencies - removed unnecessary Python packages
* New upstream release 1.4.4
* Dynamic terminal sizing for web interface
* Real-time terminal resize support
* Force echo mode for SSH connections
* Enhanced logging with logrotate integration
* Fixed terminal dimensions and echo handling
* Standalone PyInstaller binary with bundled dependencies
* Fixed Makefile syntax errors and directory creation issues
* Added binary reuse logic for efficient package building
......
# Automatically added by dh_installsystemd/13.26
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
# The following line should be removed in trixie or trixie+1
deb-systemd-helper unmask 'wssshd.service' >/dev/null || true
# was-enabled defaults to true, so new installations run enable.
if deb-systemd-helper --quiet was-enabled 'wssshd.service'; then
# Enables the unit on first installation, creates new
# symlinks on upgrades if the unit file has changed.
deb-systemd-helper enable 'wssshd.service' >/dev/null || true
else
# Update the statefile to add new symlinks (if any), which need to be
# cleaned up on purge. Also remove old symlinks.
deb-systemd-helper update-state 'wssshd.service' >/dev/null || true
fi
fi
# End automatically added section
# Automatically added by dh_installsystemd/13.26
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
if [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true
if [ -n "$2" ]; then
_dh_action=restart
else
_dh_action=start
fi
deb-systemd-invoke $_dh_action 'wssshd.service' >/dev/null || true
fi
fi
# End automatically added section
# Automatically added by dh_installsystemd/13.26
if [ -z "$DPKG_ROOT" ] && [ "$1" = remove ] && [ -d /run/systemd/system ] ; then
deb-systemd-invoke stop 'wssshd.service' >/dev/null || true
fi
# End automatically added section
wsssh-server_1.4.4-1_amd64.buildinfo net optional
wsssh-server_1.4.4-1_amd64.deb net optional
# Automatically added by dh_installsystemd/13.26
if [ "$1" = remove ] && [ -d /run/systemd/system ] ; then
systemctl --system daemon-reload >/dev/null || true
fi
# End automatically added section
# Automatically added by dh_installsystemd/13.26
if [ "$1" = "purge" ]; then
if [ -x "/usr/bin/deb-systemd-helper" ]; then
deb-systemd-helper purge 'wssshd.service' >/dev/null || true
fi
fi
# End automatically added section
# Automatically added by dh_installdebconf/13.26
if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then
. /usr/share/debconf/confmodule
db_purge
fi
# End automatically added section
misc:Depends=debconf (>= 0.5) | debconf-2.0
shlibs:Depends=libc6 (>= 2.14), zlib1g (>= 1:1.1.4)
misc:Pre-Depends=
/etc/default/wssshd
/etc/init.d/wssshd
/etc/logrotate.d/wssshd
Package: wsssh-server
Version: 1.4.4-1
Architecture: amd64
Maintainer: Stefy Lanza <stefy@nexlab.net>
Installed-Size: 26704
Depends: libc6 (>= 2.14), zlib1g (>= 1:1.1.4), debconf (>= 0.5) | debconf-2.0, adduser
Section: net
Priority: optional
Homepage: https://git.nexlab.net/nexlab/wsssh
Description: WebSocket SSH Server (wssshd)
A modern SSH tunneling system that provides WebSocket-based SSH/SCP access
to registered client machines. This package contains the server component
that handles WebSocket connections and manages SSH tunnels.
.
This package includes a standalone PyInstaller binary that bundles all
required dependencies, eliminating the need for external Python packages.
.
The wssshd server provides:
- WebSocket SSH tunnel management
- Client registration and authentication
- Web-based management interface
- Secure tunnel establishment between clients and servers
- High availability with watchdog monitoring
.
This is the server component of the WebSocket SSH system.
5b28c390af6ad414bbc6d868f644c127 lib/systemd/system/wssshd.service
d438ff148b99e19c3435b1fe36f24213 usr/bin/wssshd
0ca10988f88229f2118de364159866bd usr/sbin/wssshd-watchdog
81d71d8ec53e6a9ea3daad365eadfb55 usr/share/doc/wsssh-server/changelog.Debian.gz
929c14c9c965f9fca6385eb474c66835 usr/share/doc/wsssh-server/copyright
6771c7ff8f7526f370e92b5234b6611f usr/share/man/man1/wssshd.1.gz
5544f281baa6984b433fe312936524ad usr/share/wsssh/logos/banner-800x200.png
fbae8873c0f4be974ba0710a4431e55c usr/share/wsssh/logos/favicon.ico
52653de9c01c19cd8ebc223a75979736 usr/share/wsssh/logos/icon-128.png
8341d1c90883c14f96fc3c931bff98aa usr/share/wsssh/logos/icon-16.png
0127cf332e8910251c2f8ce1b37af725 usr/share/wsssh/logos/icon-256.png
0985ae2de553ed4628c8a2244922229e usr/share/wsssh/logos/icon-32.png
bcfca95aa4a79b07c1b609d8d91c01f8 usr/share/wsssh/logos/icon-48.png
a6867c9fabaa85db279580b874ba26fb usr/share/wsssh/logos/icon-64.png
52653de9c01c19cd8ebc223a75979736 usr/share/wsssh/logos/logo-128.png
0127cf332e8910251c2f8ce1b37af725 usr/share/wsssh/logos/logo-256.png
283f0c055eff7e299d06120d5913a406 usr/share/wsssh/logos/logo-512.png
a6867c9fabaa85db279580b874ba26fb usr/share/wsssh/logos/logo-64.png
bd58776dc9820c39a46fd51316461fe2 usr/share/wsssh/logos/logo-high-quality.png
07ebae287e8a4882deb22c0223aa6310 usr/share/wsssh/templates/base.html
b98475a970285d499246a8627535a4cf usr/share/wsssh/templates/index.html
dd0dcf5219c6ab94aba6ca0da3186e1e usr/share/wsssh/templates/login.html
f3c419734db44fa03bfaeac866e8287b usr/share/wsssh/templates/terminal.html
42130d3c1a8324daa7cacc004a512650 usr/share/wsssh/templates/users.html
d942cd2a28bf0beee87fe688be0ecc2d usr/share/wsssh/wssshd.conf.example
#!/bin/sh
# postinst script for wsssh-server
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <package-being-installed> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
configure)
# Create wssshd user and group if they don't exist
if ! getent group wssshd >/dev/null 2>&1; then
addgroup --system wssshd
fi
if ! getent passwd wssshd >/dev/null 2>&1; then
adduser --system --ingroup wssshd --home /var/lib/wssshd \
--no-create-home --shell /bin/false wssshd
fi
# Create wssshd home directory
if [ ! -d /var/lib/wssshd ]; then
mkdir -p /var/lib/wssshd
fi
# Ensure wssshd user owns its home directory and can write to it
chown wssshd:wssshd /var/lib/wssshd
chmod 755 /var/lib/wssshd
# Ensure the user can actually write to its home directory
# Try to create a test file to verify write permissions
if ! su -s /bin/sh wssshd -c "touch /var/lib/wssshd/.test_write 2>/dev/null && rm /var/lib/wssshd/.test_write 2>/dev/null" 2>/dev/null; then
echo "Warning: wssshd user cannot write to /var/lib/wssshd, fixing permissions"
# Try to fix permissions by making directory writable
chmod 775 /var/lib/wssshd
# Also ensure the user is in the right group
usermod -g wssshd wssshd 2>/dev/null || true
fi
# Create log directory
if [ ! -d /var/log/wssshd ]; then
mkdir -p /var/log/wssshd
chown wssshd:wssshd /var/log/wssshd
chmod 755 /var/log/wssshd
fi
# Create configuration directory
if [ ! -d /etc/wssshd ]; then
mkdir -p /etc/wssshd
chown wssshd:wssshd /etc/wssshd
chmod 755 /etc/wssshd
fi
# Create /etc/default/wssshd if it doesn't exist
if [ ! -f /etc/default/wssshd ]; then
cat > /etc/default/wssshd << EOF
# WebSocket SSH Server (wssshd) configuration
# Set to Y, 1, TRUE, true, YES, or yes to enable the service
START=no
# Additional configuration can be done in /etc/wssshd.conf
EOF
chmod 644 /etc/default/wssshd
fi
# Create example configuration file if it doesn't exist
if [ ! -f /etc/wssshd.conf.example ]; then
if [ -f /usr/share/wsssh/wssshd.conf.example ]; then
cp /usr/share/wsssh/wssshd.conf.example /etc/wssshd.conf.example
chmod 644 /etc/wssshd.conf.example
fi
fi
# Set up init script
if [ -x /etc/init.d/wssshd ]; then
update-rc.d wssshd defaults >/dev/null 2>&1 || true
fi
# Enable systemd service if available and sysv init is not active
if [ -f /lib/systemd/system/wssshd.service ] && command -v systemctl >/dev/null 2>&1; then
if ! systemctl is-active wssshd >/dev/null 2>&1 && [ ! -f /var/run/wssshd-watchdog.pid ]; then
systemctl enable wssshd.service >/dev/null 2>&1 || true
fi
fi
# Set proper permissions on binary
if [ -f /usr/bin/wssshd ]; then
chown wssshd:wssshd /usr/bin/wssshd
chmod 755 /usr/bin/wssshd
fi
# Install watchdog script
if [ -f /usr/sbin/wssshd-watchdog ]; then
chown wssshd:wssshd /usr/sbin/wssshd-watchdog
chmod 755 /usr/sbin/wssshd-watchdog
fi
# Create database directory if it doesn't exist
if [ ! -d /var/lib/wssshd/db ]; then
mkdir -p /var/lib/wssshd/db
chown wssshd:wssshd /var/lib/wssshd/db
chmod 755 /var/lib/wssshd/db
fi
# Restart service if it was running before upgrade
if [ -f /tmp/wsssh-server-upgrade-state ]; then
. /tmp/wsssh-server-upgrade-state
rm -f /tmp/wsssh-server-upgrade-state
if [ "$WSSSHD_WAS_RUNNING" = "1" ]; then
echo "Restarting wssshd service after upgrade..."
if [ -x /etc/init.d/wssshd ]; then
/etc/init.d/wssshd start || true
fi
fi
fi
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
# Automatically added by dh_installsystemd/13.26
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
# The following line should be removed in trixie or trixie+1
deb-systemd-helper unmask 'wssshd.service' >/dev/null || true
# was-enabled defaults to true, so new installations run enable.
if deb-systemd-helper --quiet was-enabled 'wssshd.service'; then
# Enables the unit on first installation, creates new
# symlinks on upgrades if the unit file has changed.
deb-systemd-helper enable 'wssshd.service' >/dev/null || true
else
# Update the statefile to add new symlinks (if any), which need to be
# cleaned up on purge. Also remove old symlinks.
deb-systemd-helper update-state 'wssshd.service' >/dev/null || true
fi
fi
# End automatically added section
# Automatically added by dh_installsystemd/13.26
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
if [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true
if [ -n "$2" ]; then
_dh_action=restart
else
_dh_action=start
fi
deb-systemd-invoke $_dh_action 'wssshd.service' >/dev/null || true
fi
fi
# End automatically added section
exit 0
\ No newline at end of file
#!/bin/sh
# postrm script for wsssh-server
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <overwriter>
# <overwriter-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
# Stop the service if it's running
if [ -x /etc/init.d/wssshd ]; then
invoke-rc.d wssshd stop >/dev/null 2>&1 || true
fi
# Remove init script symlinks
if [ -x /etc/init.d/wssshd ]; then
update-rc.d wssshd remove >/dev/null 2>&1 || true
fi
# Remove user and group on purge
if [ "$1" = "purge" ]; then
# Remove wssshd user and group
if getent passwd wssshd >/dev/null 2>&1; then
deluser wssshd || true
fi
if getent group wssshd >/dev/null 2>&1; then
delgroup wssshd || true
fi
# Remove configuration and data directories
rm -rf /var/lib/wssshd
rm -rf /var/log/wssshd
rm -rf /etc/wssshd
# Remove configuration files
rm -f /etc/default/wssshd
rm -f /etc/wssshd.conf
rm -f /etc/wssshd.conf.example
fi
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
# Automatically added by dh_installsystemd/13.26
if [ "$1" = remove ] && [ -d /run/systemd/system ] ; then
systemctl --system daemon-reload >/dev/null || true
fi
# End automatically added section
# Automatically added by dh_installsystemd/13.26
if [ "$1" = "purge" ]; then
if [ -x "/usr/bin/deb-systemd-helper" ]; then
deb-systemd-helper purge 'wssshd.service' >/dev/null || true
fi
fi
# End automatically added section
# Automatically added by dh_installdebconf/13.26
if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then
. /usr/share/debconf/confmodule
db_purge
fi
# End automatically added section
exit 0
\ No newline at end of file
#!/bin/sh
# preinst script for wsssh-server
set -e
# summary of how this script can be called:
# * <new-preinst> `install'
# * <new-preinst> `install' <old-version>
# * <new-preinst> `upgrade' <old-version>
# * <old-preinst> `abort-upgrade' <new-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
WSSSHD_RUNNING=0
case "$1" in
install|upgrade)
# Check if wssshd service is running before upgrade
if [ -x /etc/init.d/wssshd ]; then
if /etc/init.d/wssshd status >/dev/null 2>&1; then
WSSSHD_RUNNING=1
# Check if we're in a non-interactive environment
if [ -n "$DEBIAN_FRONTEND" ] && [ "$DEBIAN_FRONTEND" = "noninteractive" ]; then
echo "Non-interactive environment detected, stopping wssshd service automatically..."
/etc/init.d/wssshd stop || true
sleep 2
else
# Use debconf to ask user for confirmation
. /usr/share/debconf/confmodule
db_input medium wsssh-server/stop-service || true
db_go || true
# Get the user's answer
db_get wsssh-server/stop-service
if [ "$RET" = "true" ] || [ -z "$RET" ]; then
echo "Stopping wssshd service for upgrade..."
/etc/init.d/wssshd stop || true
# Give it a moment to fully stop
sleep 2
else
echo "User declined to stop wssshd service. Upgrade may fail."
echo "You can manually stop the service with: sudo /etc/init.d/wssshd stop"
echo "Then retry the upgrade."
exit 1
fi
fi
fi
fi
;;
abort-upgrade)
;;
*)
echo "preinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# Store the running state for postinst
if [ "$WSSSHD_RUNNING" = "1" ]; then
echo "WSSSHD_WAS_RUNNING=1" > /tmp/wsssh-server-upgrade-state
else
echo "WSSSHD_WAS_RUNNING=0" > /tmp/wsssh-server-upgrade-state
fi
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
exit 0
\ No newline at end of file
#!/bin/sh
set -e
# Automatically added by dh_installsystemd/13.26
if [ -z "$DPKG_ROOT" ] && [ "$1" = remove ] && [ -d /run/systemd/system ] ; then
deb-systemd-invoke stop 'wssshd.service' >/dev/null || true
fi
# End automatically added section
Template: wsssh-server/stop-service
Type: boolean
Default: true
Description: Stop wssshd service during upgrade?
The wssshd service is currently running. To upgrade the package safely,
the service needs to be stopped temporarily. It will be restarted
automatically after the upgrade is complete.
.
Should the wssshd service be stopped now?
.
This question will be skipped in non-interactive environments, and the
service will be stopped automatically for safe upgrades.
\ No newline at end of file
# WebSocket SSH Server (wssshd) configuration
# Set to Y, 1, TRUE, true, YES, or yes to enable the service
START=no
# Additional configuration can be done in /etc/wssshd.conf
\ No newline at end of file
#!/bin/bash
#
# wssshd Startup script for WebSocket SSH Daemon
#
# chkconfig: 345 85 15
# description: WebSocket SSH Daemon - Handles WebSocket connections from wsssh/wsscp clients
# processname: wssshd
# pidfile: /var/run/wssshd.pid
# config: /etc/wssshd.conf
### BEGIN INIT INFO
# Provides: wssshd
# Required-Start: $local_fs $network $syslog
# Required-Stop: $local_fs $network $syslog
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Short-Description: WebSocket SSH Daemon
# Description: WebSocket SSH Daemon handles WebSocket connections from wsssh/wsscp clients
### END INIT INFO
# Source function library (Debian/Ubuntu)
. /lib/lsb/init-functions
# Configuration
NAME="wssshd"
DAEMON="/usr/bin/wssshd"
WATCHDOG="/usr/sbin/wssshd-watchdog"
PIDFILE="/var/run/wssshd.pid"
WATCHDOG_PIDFILE="/var/run/wssshd-watchdog.pid"
CONFIG="/etc/wssshd.conf"
LOG_FACILITY="daemon"
USER="wssshd"
GROUP="wssshd"
# Check if we're running as root
if [ $(id -u) != 0 ]; then
echo "Error: This script must be run as root"
exit 1
fi
# Function to check if process is running
is_running() {
if [ -f "$PIDFILE" ]; then
local pid=$(cat "$PIDFILE")
if [ -d "/proc/$pid" ]; then
return 0
else
# Stale PID file
rm -f "$PIDFILE"
return 1
fi
fi
return 1
}
# Function to start the daemon
start() {
echo -n "Starting $NAME: "
# Check if daemon is already running
if is_running; then
local pid=$(cat "$PIDFILE")
echo "already running (PID: $pid)"
return 0
fi
# Check if config file exists
if [ ! -f "$CONFIG" ]; then
echo "configuration file $CONFIG not found"
echo "Please create $CONFIG with the required settings."
echo "You can use the example configuration as a template:"
echo " cp /usr/share/wsssh/wssshd.conf.example $CONFIG"
return 1
fi
# Check if daemon executable exists
if [ ! -x "$DAEMON" ]; then
echo "daemon executable $DAEMON not found or not executable"
return 1
fi
# Create necessary directories
mkdir -p /var/run /var/log/wssshd
chown $USER:$GROUP /var/run /var/log/wssshd 2>/dev/null || true
# Start the daemon directly
echo "Starting daemon..."
if start-stop-daemon --start --quiet --pidfile "$PIDFILE" \
--chuid $USER:$GROUP --background --make-pidfile \
--exec "$DAEMON" --output /var/log/wssshd/wssshd.log; then
echo "Daemon started successfully"
else
echo "start-stop-daemon failed, trying direct execution..."
if "$DAEMON" >> /var/log/wssshd/wssshd.log 2>&1 &
then
echo $! > "$PIDFILE"
echo "Daemon started successfully (direct execution)"
else
echo "FAILED"
echo "Could not start daemon"
return 1
fi
fi
# Wait for daemon to be fully running
local count=0
while [ $count -lt 10 ] && ! is_running; do
echo "Waiting for daemon to start... ($count/10)"
sleep 1
count=$((count + 1))
done
if is_running; then
local pid=$(cat "$PIDFILE")
echo "Daemon is running (PID: $pid)"
# Stop any existing watchdog before starting a new one
if [ -f "$WATCHDOG_PIDFILE" ] || pgrep -f "wssshd-watchdog" >/dev/null 2>&1; then
echo "Stopping existing watchdog..."
$WATCHDOG stop >/dev/null 2>&1
sleep 2
fi
# Now start the watchdog to monitor the running daemon
echo "Starting watchdog..."
if [ -x "$WATCHDOG" ]; then
$WATCHDOG start >/dev/null 2>&1
# Wait for watchdog PID file to be created (max 5 seconds)
local count=0
while [ $count -lt 10 ] && [ ! -f "$WATCHDOG_PIDFILE" ]; do
sleep 0.5
count=$((count + 1))
done
if [ -f "$WATCHDOG_PIDFILE" ]; then
watchdog_pid=$(cat "$WATCHDOG_PIDFILE" 2>/dev/null)
if [ -n "$watchdog_pid" ] && kill -0 "$watchdog_pid" 2>/dev/null; then
echo "OK"
return 0
else
echo "OK (daemon running, watchdog process not responding)"
return 0
fi
else
echo "OK (daemon running, watchdog PID file not found)"
return 0
fi
else
echo "OK (daemon running, no watchdog available)"
return 0
fi
else
echo "FAILED"
echo "Daemon failed to start properly"
return 1
fi
}
# Function to stop the daemon
stop() {
echo -n "Stopping $NAME: "
# First, try to stop the watchdog if it's running
if [ -f "$WATCHDOG_PIDFILE" ]; then
echo "Stopping watchdog..."
$WATCHDOG stop >/dev/null 2>&1
sleep 2
fi
# Check if daemon is running via PID file
if is_running; then
echo "Stopping daemon via PID file..."
local pid=$(cat "$PIDFILE")
# Try to stop gracefully first
kill -TERM "$pid" 2>/dev/null
sleep 2
# Check if it's still running
if kill -0 "$pid" 2>/dev/null; then
# Force kill if still running
kill -KILL "$pid" 2>/dev/null
sleep 1
fi
fi
# Also kill any wssshd processes that might be running (regardless of PID file)
echo "Ensuring all wssshd processes are stopped..."
pkill -TERM -f "^/usr/bin/wssshd" 2>/dev/null || true
sleep 2
pkill -KILL -f "^/usr/bin/wssshd" 2>/dev/null || true
# Clean up PID files
rm -f "$PIDFILE" "$WATCHDOG_PIDFILE"
# Final check
if is_running; then
echo "FAILED"
return 1
else
echo "OK"
return 0
fi
}
# Function to restart the daemon
restart() {
stop
sleep 2
start
}
# Function to check status
status() {
# Check watchdog status
if [ -f "$WATCHDOG_PIDFILE" ]; then
local watchdog_pid=$(cat "$WATCHDOG_PIDFILE")
if kill -0 "$watchdog_pid" 2>/dev/null; then
echo "Watchdog is running (PID: $watchdog_pid)"
else
echo "Watchdog PID file exists but process is not running"
rm -f "$WATCHDOG_PIDFILE"
fi
else
echo "Watchdog is not running"
fi
# Check daemon status
if is_running; then
local pid=$(cat "$PIDFILE")
echo "$NAME daemon is running (PID: $pid)"
return 0
else
echo "$NAME daemon is not running"
return 3
fi
}
# Function to reload configuration
reload() {
echo -n "Reloading $NAME configuration: "
if ! is_running; then
echo "not running"
return 1
fi
local pid=$(cat "$PIDFILE")
kill -HUP $pid 2>/dev/null
if [ $? -eq 0 ]; then
echo "OK"
return 0
else
echo "FAILED"
return 1
fi
}
# Main script logic
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
reload)
reload
;;
status)
status
;;
condrestart|try-restart)
if is_running; then
restart
fi
;;
*)
echo "Usage: $0 {start|stop|restart|reload|status|condrestart}"
exit 2
;;
esac
exit $?
\ No newline at end of file
/var/log/wssshd/wssshd.log {
weekly
missingok
rotate 52
compress
delaycompress
notifempty
create 644 wssshd wssshd
postrotate
if [ -f /var/run/wssshd.pid ]; then
kill -HUP $(cat /var/run/wssshd.pid) 2>/dev/null || true
fi
endscript
}
/var/log/wssshd/watchdog.log {
weekly
missingok
rotate 52
compress
delaycompress
notifempty
create 644 wssshd wssshd
postrotate
if [ -f /var/run/wssshd-watchdog.pid ]; then
kill -HUP $(cat /var/run/wssshd-watchdog.pid) 2>/dev/null || true
fi
endscript
}
\ No newline at end of file
[Unit]
Description=WebSocket SSH Daemon
After=network.target syslog.target
Requires=network.target
ConditionPathExists=!/etc/init.d/wssshd
ConditionPathExists=!/var/run/wssshd-watchdog.pid
[Service]
Type=forking
User=wssshd
Group=wssshd
EnvironmentFile=-/etc/default/wssshd
ExecStart=/usr/sbin/wssshd-watchdog start
ExecStop=/usr/sbin/wssshd-watchdog stop
ExecReload=/usr/sbin/wssshd-watchdog restart
PIDFile=/var/run/wssshd-watchdog.pid
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
\ No newline at end of file
This diff is collapsed.
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: wsssh-server
Upstream-Contact: Stefy Lanza <stefy@nexlab.net>
Source: https://github.com/stefy/wsssh
Files: *
Copyright: 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
License: GPL-3.0+
Files: debian/*
Copyright: 2024 Stefy Lanza <stefy@nexlab.net>
License: GPL-3.0+
License: GPL-3.0+
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 package 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/>.
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}WebSocket SSH Daemon{% endblock %}</title>
<link rel="icon" href="/logos/favicon.ico" type="image/x-icon">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css">
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script>
<style>
.navbar-brand {
font-weight: bold;
}
.client-card {
transition: transform 0.2s;
}
.client-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.terminal-container {
background-color: #1e1e1e;
color: #f8f8f2;
font-family: 'Courier New', monospace;
border-radius: 8px;
height: calc(100vh - 200px);
min-height: 400px;
overflow: hidden;
position: relative;
}
.terminal-input {
background: transparent;
border: none;
color: #f8f8f2;
font-family: 'Courier New', monospace;
width: 100%;
outline: none;
}
.terminal-input:focus {
box-shadow: none;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="{{ url_for('index') }}">
<i class="fas fa-terminal"></i> WebSocket SSH Daemon
</a>
<div class="navbar-nav ms-auto">
{% if current_user.is_authenticated %}
<span class="navbar-text me-3">
Welcome, {{ current_user.username }}!
</span>
<button class="btn btn-outline-warning btn-sm me-2" data-bs-toggle="modal" data-bs-target="#donationModal">
<i class="fas fa-heart"></i> Donate
</button>
<a class="nav-link" href="{{ url_for('logout') }}">
<i class="fas fa-sign-out-alt"></i> Logout
</a>
{% endif %}
</div>
</div>
</nav>
<div class="container mt-4">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ 'danger' if category == 'error' else 'info' }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</div>
<!-- Donation Modal -->
<div class="modal fade" id="donationModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-heart text-danger"></i> Support WebSocket SSH Development
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p class="text-muted">Your support helps us continue developing and maintaining this open-source project!</p>
<div class="row">
<div class="col-md-4 text-center mb-3">
<h6><i class="fab fa-paypal text-primary"></i> PayPal</h6>
<a href="https://www.paypal.com/paypalme/nexlab" target="_blank" class="btn btn-primary btn-sm">
<i class="fab fa-paypal"></i> Donate via PayPal
</a>
<small class="d-block text-muted mt-1">info@nexlab.net</small>
</div>
<div class="col-md-4 text-center mb-3">
<h6><i class="fab fa-bitcoin text-warning"></i> Bitcoin</h6>
<div class="mb-2">
<img src="https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=bitcoin:bc1q3zlkpu95amtcltsk85y0eacyzzk29v68tgc5hx" alt="BTC QR Code" class="img-fluid rounded">
</div>
<div class="input-group input-group-sm">
<input type="text" class="form-control form-control-sm font-monospace" value="bc1q3zlkpu95amtcltsk85y0eacyzzk29v68tgc5hx" readonly style="font-size: 0.75rem;">
<button class="btn btn-outline-secondary btn-sm" type="button" onclick="copyToClipboard('bc1q3zlkpu95amtcltsk85y0eacyzzk29v68tgc5hx')">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="col-md-4 text-center mb-3">
<h6><i class="fab fa-ethereum text-secondary"></i> Ethereum</h6>
<div class="mb-2">
<img src="https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=ethereum:0xdA6dAb526515b5cb556d20269207D43fcc760E51" alt="ETH QR Code" class="img-fluid rounded">
</div>
<div class="input-group input-group-sm">
<input type="text" class="form-control form-control-sm font-monospace" value="0xdA6dAb526515b5cb556d20269207D43fcc760E51" readonly style="font-size: 0.75rem;">
<button class="btn btn-outline-secondary btn-sm" type="button" onclick="copyToClipboard('0xdA6dAb526515b5cb556d20269207D43fcc760E51')">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
</div>
<hr>
<p class="text-center mb-0">
<small class="text-muted">
Thank you for your support! ❤️
</small>
</p>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script>
<script>
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(function() {
// Show a temporary success message
const btn = event.target.closest('button');
const originalHtml = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-check"></i>';
btn.classList.remove('btn-outline-secondary');
btn.classList.add('btn-success');
setTimeout(() => {
btn.innerHTML = originalHtml;
btn.classList.remove('btn-success');
btn.classList.add('btn-outline-secondary');
}, 1000);
});
}
</script>
{% block scripts %}{% endblock %}
</body>
</html>
\ No newline at end of file
{% extends "base.html" %}
{% block title %}Dashboard - WebSocket SSH Daemon{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h3 class="card-title mb-0">
<i class="fas fa-server"></i> Connected Clients
</h3>
</div>
<div class="card-body">
{% if clients %}
<div class="row">
{% for client in clients %}
<div class="col-md-4 mb-3">
<div class="card client-card h-100">
<div class="card-body text-center">
<i class="fas fa-desktop fa-3x text-success mb-3"></i>
<h5 class="card-title">{{ client }}</h5>
<p class="card-text text-muted">Connected</p>
<a href="{{ url_for('terminal', client_id=client) }}" class="btn btn-primary">
<i class="fas fa-terminal"></i> Connect
</a>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-5">
<i class="fas fa-server fa-4x text-muted mb-3"></i>
<h4 class="text-muted">No clients connected</h4>
<p class="text-muted">Clients will appear here when they connect to the daemon.</p>
</div>
{% endif %}
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h3 class="card-title mb-0">
<i class="fas fa-cogs"></i> Quick Actions
</h3>
</div>
<div class="card-body">
{% if current_user.is_admin %}
<a href="{{ url_for('users') }}" class="btn btn-outline-primary btn-sm mb-2 w-100">
<i class="fas fa-users"></i> Manage Users
</a>
{% endif %}
<button class="btn btn-outline-secondary btn-sm w-100" onclick="location.reload()">
<i class="fas fa-sync"></i> Refresh Status
</button>
</div>
</div>
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title mb-0">
<i class="fas fa-info-circle"></i> System Info
</h3>
</div>
<div class="card-body">
<p class="mb-1"><strong>WebSocket Port:</strong> <span id="websocket-port">{{ websocket_port or 'N/A' }}</span></p>
<p class="mb-1"><strong>Domain:</strong> <span id="domain">{{ domain or 'N/A' }}</span></p>
<p class="mb-0"><strong>Connected Clients:</strong> <span id="client-count">{{ clients|length }}</span></p>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
let currentClients = {{ clients|tojson }};
function updateClients() {
fetch('/api/clients')
.then(response => response.json())
.then(data => {
// Update client count
document.getElementById('client-count').textContent = data.count;
// Check if client list changed
if (JSON.stringify(data.clients.sort()) !== JSON.stringify(currentClients.sort())) {
// Reload the page to show updated client list
location.reload();
}
})
.catch(error => {
console.log('Error fetching client data:', error);
});
}
// Update every 5 seconds
setInterval(updateClients, 5000);
// Initial update after 1 second
setTimeout(updateClients, 1000);
</script>
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% block title %}Login - WebSocket SSH Daemon{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h3 class="card-title mb-0"><i class="fas fa-sign-in-alt"></i> Login</h3>
</div>
<div class="card-body">
<form method="post">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i> Login
</button>
</form>
<div class="mt-3">
<small class="text-muted">
Default credentials: admin / admin123
</small>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% block title %}Terminal - {{ client_id }}{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center">
<a href="{{ url_for('index') }}" class="btn btn-outline-secondary btn-sm me-3">
<i class="fas fa-arrow-left"></i> Back to Dashboard
</a>
<h3 class="card-title mb-0">
<i class="fas fa-terminal"></i> SSH Terminal - {{ client_id }}
</h3>
</div>
<div>
<input type="text" id="sshUsername" class="form-control form-control-sm d-inline-block w-auto me-2" placeholder="Username" value="root">
<button id="connectBtn" class="btn btn-success btn-sm">
<i class="fas fa-play"></i> Connect
</button>
<button id="disconnectBtn" class="btn btn-danger btn-sm" disabled>
<i class="fas fa-stop"></i> Disconnect
</button>
</div>
</div>
<div class="card-body p-2">
<div id="terminal" class="terminal-container w-100"></div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
let term = null;
let connected = false;
let requestId = null;
let pollInterval = null;
document.getElementById('connectBtn').addEventListener('click', connect);
document.getElementById('disconnectBtn').addEventListener('click', disconnect);
function connect() {
const username = document.getElementById('sshUsername').value;
if (!username) {
alert('Please enter a username');
return;
}
// Initialize xterm with proper configuration
if (!term) {
term = new Terminal({
cursorBlink: true,
cursorStyle: 'block',
fontSize: 14,
fontFamily: 'Monaco, Menlo, "Ubuntu Mono", monospace',
theme: {
background: '#1e1e1e',
foreground: '#f8f8f2',
cursor: '#f8f8f2',
cursorAccent: '#1e1e1e',
selection: 'rgba(248, 248, 242, 0.3)'
},
allowTransparency: true,
scrollback: 1000,
tabStopWidth: 4,
convertEol: true,
disableStdin: false,
cursorWidth: 2,
bellStyle: 'none',
rightClickSelectsWord: true,
fastScrollModifier: 'alt',
fastScrollSensitivity: 5,
screenReaderMode: false,
macOptionIsMeta: false,
macOptionClickForcesSelection: false,
minimumContrastRatio: 1
});
term.open(document.getElementById('terminal'));
// Load fit addon
const fitAddon = new FitAddon.FitAddon();
term.loadAddon(fitAddon);
// Fit terminal to container
function fitTerminal() {
fitAddon.fit();
}
// Initial fit after a short delay to ensure DOM is ready
setTimeout(() => {
fitTerminal();
// Calculate dimensions after initial fit
const initialDimensions = fitAddon.proposeDimensions();
term._initialCols = initialDimensions.cols || 80;
term._initialRows = initialDimensions.rows || 24;
}, 100);
// Fit on window resize and update backend terminal size
window.addEventListener('resize', () => {
fitTerminal();
// Update terminal size on backend if connected
if (connected && requestId) {
const newDimensions = fitAddon.proposeDimensions();
const newCols = newDimensions.cols || 80;
const newRows = newDimensions.rows || 24;
fetch('/terminal/{{ client_id }}/resize', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'request_id=' + encodeURIComponent(requestId) +
'&cols=' + encodeURIComponent(newCols) +
'&rows=' + encodeURIComponent(newRows)
}).catch(error => {
console.error('Resize error:', error);
});
}
});
term.focus();
}
term.write('Connecting to ' + username + '@{{ client_id }}...\r\n');
connected = true;
document.getElementById('connectBtn').disabled = true;
document.getElementById('disconnectBtn').disabled = false;
document.getElementById('sshUsername').disabled = true;
// Use calculated dimensions (either from initial fit or current)
const cols = term._initialCols || fitAddon.proposeDimensions().cols || 80;
const rows = term._initialRows || fitAddon.proposeDimensions().rows || 24;
// Send connect request with terminal dimensions
fetch('/terminal/{{ client_id }}/connect', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'username=' + encodeURIComponent(username) +
'&cols=' + encodeURIComponent(cols) +
'&rows=' + encodeURIComponent(rows)
})
.then(response => response.json())
.then(data => {
if (data.request_id) {
requestId = data.request_id;
if (data.command) {
term.write('Launching: ' + data.command + '\r\n');
}
term.write('Connected successfully!\r\n$ ');
// Start polling for data with shorter interval for better responsiveness
pollInterval = setInterval(pollData, 100);
} else {
term.write('Error: ' + data.error + '\r\n');
disconnect();
}
})
.catch(error => {
term.write('Connection failed: ' + error + '\r\n');
disconnect();
});
// Handle input - send all keystrokes to server, let SSH handle echo
term.onData(data => {
if (!connected || !requestId) return;
// Send all input to server, let SSH handle echo and display
fetch('/terminal/{{ client_id }}/data', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'request_id=' + encodeURIComponent(requestId) + '&data=' + encodeURIComponent(data)
});
});
}
function disconnect() {
connected = false;
document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true;
document.getElementById('sshUsername').disabled = false;
if (pollInterval) {
clearInterval(pollInterval);
pollInterval = null;
}
if (requestId) {
fetch('/terminal/{{ client_id }}/disconnect', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'request_id=' + encodeURIComponent(requestId)
});
requestId = null;
}
if (term) {
term.write('\r\nDisconnected.\r\n');
}
}
function pollData() {
if (!requestId) return;
fetch('/terminal/{{ client_id }}/data?request_id=' + encodeURIComponent(requestId))
.then(response => response.text())
.then(data => {
if (data) {
// Let the server handle all echo and display logic
term.write(data.replace(/\n/g, '\r\n'));
}
})
.catch(error => {
console.error('Polling error:', error);
});
}
// Focus on terminal when connected
document.addEventListener('keydown', function(e) {
if (connected && term) {
term.focus();
}
});
</script>
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% block title %}User Management - WebSocket SSH Daemon{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h3 class="card-title mb-0">
<i class="fas fa-users"></i> User Management
</h3>
<div>
<a href="{{ url_for('index') }}" class="btn btn-outline-secondary btn-sm me-2">
<i class="fas fa-home"></i> Back to Home
</a>
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addUserModal">
<i class="fas fa-plus"></i> Add User
</button>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Username</th>
<th>Role</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user.username }}</td>
<td>
{% if user.is_admin %}
<span class="badge bg-danger">Admin</span>
{% else %}
<span class="badge bg-secondary">User</span>
{% endif %}
</td>
<td>
<button class="btn btn-sm btn-outline-primary" onclick="editUser({{ user.id }}, '{{ user.username }}', {{ user.is_admin|lower }})">
<i class="fas fa-edit"></i> Edit
</button>
{% if user.username != current_user.username %}
<button class="btn btn-sm btn-outline-danger" onclick="deleteUser({{ user.id }}, '{{ user.username }}')">
<i class="fas fa-trash"></i> Delete
</button>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Add User Modal -->
<div class="modal fade" id="addUserModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add New User</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="addUserForm">
<div class="modal-body">
<div class="mb-3">
<label for="addUsername" class="form-label">Username</label>
<input type="text" class="form-control" id="addUsername" name="username" required>
</div>
<div class="mb-3">
<label for="addPassword" class="form-label">Password</label>
<input type="password" class="form-control" id="addPassword" name="password" required>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="addIsAdmin" name="is_admin">
<label class="form-check-label" for="addIsAdmin">Administrator</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Add User</button>
</div>
</form>
</div>
</div>
</div>
<!-- Edit User Modal -->
<div class="modal fade" id="editUserModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit User</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="editUserForm">
<input type="hidden" id="editUserId" name="user_id">
<div class="modal-body">
<div class="mb-3">
<label for="editUsername" class="form-label">Username</label>
<input type="text" class="form-control" id="editUsername" name="username" required>
</div>
<div class="mb-3">
<label for="editPassword" class="form-label">New Password (leave empty to keep current)</label>
<input type="password" class="form-control" id="editPassword" name="password">
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="editIsAdmin" name="is_admin">
<label class="form-check-label" for="editIsAdmin">Administrator</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Update User</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
function editUser(userId, username, isAdmin) {
document.getElementById('editUserId').value = userId;
document.getElementById('editUsername').value = username;
document.getElementById('editPassword').value = '';
document.getElementById('editIsAdmin').checked = isAdmin;
new bootstrap.Modal(document.getElementById('editUserModal')).show();
}
function deleteUser(userId, username) {
if (confirm(`Are you sure you want to delete user "${username}"?`)) {
fetch(`/delete_user/${userId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Error: ' + data.error);
}
});
}
}
document.getElementById('addUserForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch('/add_user', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
bootstrap.Modal.getInstance(document.getElementById('addUserModal')).hide();
location.reload();
} else {
alert('Error: ' + data.error);
}
});
});
document.getElementById('editUserForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const userId = document.getElementById('editUserId').value;
fetch(`/edit_user/${userId}`, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
bootstrap.Modal.getInstance(document.getElementById('editUserModal')).hide();
location.reload();
} else {
alert('Error: ' + data.error);
}
});
});
</script>
{% endblock %}
\ No newline at end of file
[wssshd]
host = 0.0.0.0
port = 9898
password = mysecret
domain = example.com
web-host = 0.0.0.0
web-port = 8080
web-https = false
\ No newline at end of file
Format: 1.0
Source: wsssh-server
Binary: wsssh-server
Architecture: amd64 source
Version: 1.4.4-1
Checksums-Md5:
56d229ac0c75d4d3989fa31efba60bfc 730 wsssh-server_1.4.4-1.dsc
09acdffcb0f2ce1964960c5a00c191ea 26629888 wsssh-server_1.4.4-1_amd64.deb
Checksums-Sha1:
2572508a507c5c51e6771c757880856ee541572c 730 wsssh-server_1.4.4-1.dsc
cacc524558df8a861453333cab40abddc292e1fe 26629888 wsssh-server_1.4.4-1_amd64.deb
Checksums-Sha256:
03e9a4d1e4dd2388c7d6a4254247ea949d79ba1d364e93fd36f993b890ebeefa 730 wsssh-server_1.4.4-1.dsc
e9391f5160b8dd0e5b6cc89a00b0bd99d889467ba78fb9af72d931daf0401b44 26629888 wsssh-server_1.4.4-1_amd64.deb
Build-Origin: Devuan
Build-Architecture: amd64
Build-Date: Tue, 16 Sep 2025 18:34:04 +0200
Build-Tainted-By:
usr-local-has-configs
usr-local-has-libraries
usr-local-has-programs
Installed-Build-Depends:
autoconf (= 2.72-3.1),
automake (= 1:1.17-4),
autopoint (= 0.22.5-4),
autotools-dev (= 20220109.1),
base-files (= 13.6devuan1),
base-passwd (= 3.6.6),
bash (= 5.2.37-2+b5),
binutils (= 2.43.50.20250108-1),
binutils-common (= 2.43.50.20250108-1),
binutils-x86-64-linux-gnu (= 2.43.50.20250108-1),
bsdextrautils (= 2.40.2-14devuan1),
bsdutils (= 1:2.40.2-14devuan1),
build-essential (= 12.12),
bzip2 (= 1.0.8-6),
ca-certificates (= 20241223),
clang-13 (= 1:13.0.0-9+b2),
clang-16 (= 1:16.0.6-27),
clang-19 (= 1:19.1.7-3+b1),
coreutils (= 9.5-1+b1),
cpp (= 4:14.2.0-1),
cpp-10 (= 10.5.0-4),
cpp-11 (= 11.5.0-2),
cpp-13 (= 13.3.0-12),
cpp-13-x86-64-linux-gnu (= 13.3.0-12),
cpp-14 (= 14.2.0-12),
cpp-14-x86-64-linux-gnu (= 14.2.0-12),
cpp-x86-64-linux-gnu (= 4:14.2.0-1),
dash (= 0.5.12-11),
debconf (= 1.5.89),
debhelper (= 13.26),
debianutils (= 5.21),
dh-autoreconf (= 20),
dh-strip-nondeterminism (= 1.14.2-1),
diffutils (= 1:3.10-2),
dpkg (= 1.22.13),
dpkg-dev (= 1.22.13),
dwz (= 0.15-1+b1),
file (= 1:5.45-3+b1),
findutils (= 4.10.0-3),
g++ (= 4:14.2.0-1),
g++-14 (= 14.2.0-12),
g++-14-x86-64-linux-gnu (= 14.2.0-12),
g++-x86-64-linux-gnu (= 4:14.2.0-1),
gawk (= 1:5.2.1-2+b1),
gcc (= 4:14.2.0-1),
gcc-10 (= 10.5.0-4),
gcc-10-base (= 10.5.0-4),
gcc-11 (= 11.5.0-2),
gcc-11-base (= 11.5.0-2),
gcc-13 (= 13.3.0-12),
gcc-13-base (= 13.3.0-12),
gcc-13-x86-64-linux-gnu (= 13.3.0-12),
gcc-14 (= 14.2.0-12),
gcc-14-base (= 14.2.0-12),
gcc-14-x86-64-linux-gnu (= 14.2.0-12),
gcc-x86-64-linux-gnu (= 4:14.2.0-1),
gettext (= 0.22.5-4),
gettext-base (= 0.22.5-4),
grep (= 3.11-4),
groff-base (= 1.23.0-7),
gzip (= 1.12-1.2),
hostname (= 3.25),
init-system-helpers (= 1.68devuan1),
intltool-debian (= 0.35.0+20060710.6),
lib32gcc-s1 (= 14.2.0-12),
lib32stdc++6 (= 14.2.0-12),
libacl1 (= 2.3.2-2+b1),
libarchive-zip-perl (= 1.68-1),
libasan6 (= 11.5.0-2),
libasan8 (= 14.2.0-12),
libatomic1 (= 14.2.0-12),
libattr1 (= 1:2.5.2-2),
libaudit-common (= 1:4.0.2-2),
libaudit1 (= 1:4.0.2-2),
libbinutils (= 2.43.50.20250108-1),
libblkid1 (= 2.40.2-14devuan1),
libbsd0 (= 0.12.2-2),
libbz2-1.0 (= 1.0.8-6),
libc-bin (= 2.40-5),
libc-dev-bin (= 2.40-5),
libc6 (= 2.40-5),
libc6-dev (= 2.40-5),
libc6-i386 (= 2.40-5),
libcap-ng0 (= 0.8.5-4),
libcap2 (= 1:2.66-5+b1),
libcc1-0 (= 14.2.0-12),
libclang-common-13-dev (= 1:13.0.0-9+b2),
libclang-common-16-dev (= 1:16.0.6-27),
libclang-common-19-dev (= 1:19.1.7-3+b1),
libclang-cpp13 (= 1:13.0.0-9+b2),
libclang-cpp16t64 (= 1:16.0.6-27),
libclang-cpp19 (= 1:19.1.7-3+b1),
libclang1-13 (= 1:13.0.0-9+b2),
libclang1-16t64 (= 1:16.0.6-27),
libclang1-19 (= 1:19.1.7-3+b1),
libcrypt-dev (= 1:4.4.36-5),
libcrypt1 (= 1:4.4.36-5),
libctf-nobfd0 (= 2.43.50.20250108-1),
libctf0 (= 2.43.50.20250108-1),
libdb5.3t64 (= 5.3.28+dfsg2-9),
libdebconfclient0 (= 0.277),
libdebhelper-perl (= 13.26),
libdpkg-perl (= 1.22.13),
libedit2 (= 3.1-20240808-1),
libelf1t64 (= 0.192-4),
libelogind-compat (= 255.17-2),
libelogind0 (= 255.17-2),
libeudev1 (= 3.2.14-2),
libexpat1 (= 2.6.4-1),
libffi8 (= 3.4.6-1),
libfile-stripnondeterminism-perl (= 1.14.2-1),
libgc1 (= 1:8.2.8-1),
libgcc-10-dev (= 10.5.0-4),
libgcc-11-dev (= 11.5.0-2),
libgcc-13-dev (= 13.3.0-12),
libgcc-14-dev (= 14.2.0-12),
libgcc-s1 (= 14.2.0-12),
libgdbm-compat4t64 (= 1.24-2),
libgdbm6t64 (= 1.24-2),
libgmp10 (= 2:6.3.0+dfsg-3),
libgomp1 (= 14.2.0-12),
libgprofng0 (= 2.43.50.20250108-1),
libhwasan0 (= 14.2.0-12),
libicu72 (= 72.1-6),
libisl23 (= 0.27-1),
libitm1 (= 14.2.0-12),
libjansson4 (= 2.14-2+b3),
libllvm13 (= 1:13.0.0-9+b2),
libllvm16t64 (= 1:16.0.6-27),
libllvm19 (= 1:19.1.7-3+b1),
liblsan0 (= 14.2.0-12),
liblzma5 (= 5.6.3-1+b1),
libmagic-mgc (= 1:5.45-3+b1),
libmagic1t64 (= 1:5.45-3+b1),
libmd0 (= 1.1.0-2+b1),
libmount1 (= 2.40.2-14devuan1),
libmpc3 (= 1.3.1-1+b3),
libmpfr6 (= 4.2.1-1+b2),
libncursesw6 (= 6.5-2+b1),
libobjc-11-dev (= 11.5.0-2),
libobjc-13-dev (= 13.3.0-12),
libobjc-14-dev (= 14.2.0-12),
libobjc4 (= 14.2.0-12),
libpam-modules (= 1.5.3-7+b1),
libpam-modules-bin (= 1.5.3-7+b1),
libpam-runtime (= 1.5.3-7),
libpam0g (= 1.5.3-7+b1),
libpcre2-8-0 (= 10.44-5),
libperl5.40 (= 5.40.1-5),
libpipeline1 (= 1.5.8-1),
libpython3-stdlib (= 3.13.7-1),
libpython3.13-minimal (= 3.13.7-1),
libpython3.13-stdlib (= 3.13.7-1),
libquadmath0 (= 14.2.0-12),
libreadline8t64 (= 8.2-6),
libseccomp2 (= 2.5.5-2),
libselinux1 (= 3.7-3+b1),
libsframe1 (= 2.43.50.20250108-1),
libsigsegv2 (= 2.14-1+b2),
libsmartcols1 (= 2.40.2-14devuan1),
libsqlite3-0 (= 3.46.1-6),
libssl3t64 (= 3.4.0-2),
libstdc++-11-dev (= 11.5.0-2),
libstdc++-13-dev (= 13.3.0-12),
libstdc++-14-dev (= 14.2.0-12),
libstdc++6 (= 14.2.0-12),
libtinfo6 (= 6.5-2+b1),
libtool (= 2.5.4-2),
libtsan0 (= 11.5.0-2),
libtsan2 (= 14.2.0-12),
libubsan1 (= 14.2.0-12),
libuchardet0 (= 0.0.8-1+b2),
libunistring5 (= 1.3-1),
libuuid1 (= 2.40.2-14devuan1),
libxml2 (= 2.12.7+dfsg+really2.9.14-0.2+b1),
libz3-4 (= 4.13.3-1),
libzstd1 (= 1.5.6+dfsg-2),
linux-libc-dev (= 6.12.15-1),
llvm-16-linker-tools (= 1:16.0.6-27),
llvm-19-linker-tools (= 1:19.1.7-3+b1),
m4 (= 1.4.19-5),
make (= 4.4.1-1),
man-db (= 2.13.0-1),
mawk (= 1.3.4.20240905-1),
media-types (= 10.1.0),
ncurses-base (= 6.5-2),
ncurses-bin (= 6.5-2+b1),
netbase (= 6.4),
openssl (= 3.4.0-2),
openssl-provider-legacy (= 3.4.0-2),
patch (= 2.7.6-7),
perl (= 5.40.1-5),
perl-base (= 5.40.1-5),
perl-modules-5.40 (= 5.40.1-5),
po-debconf (= 1.0.21+nmu1),
python3 (= 3.13.7-1),
python3-autocommand (= 2.2.2-3),
python3-importlib-metadata (= 8.5.0-1),
python3-inflect (= 7.3.1-2),
python3-jaraco.context (= 6.0.0-1),
python3-jaraco.functools (= 4.1.0-1),
python3-jaraco.text (= 4.0.0-1),
python3-minimal (= 3.13.7-1),
python3-more-itertools (= 10.5.0-1),
python3-packaging (= 24.2-1),
python3-pip (= 25.1.1+dfsg-1),
python3-pkg-resources (= 78.1.1-0.1),
python3-setuptools (= 78.1.1-0.1),
python3-typeguard (= 4.4.1-1),
python3-typing-extensions (= 4.12.2-2),
python3-wheel (= 0.46.1-2),
python3-zipp (= 3.21.0-1),
python3.13 (= 3.13.7-1),
python3.13-minimal (= 3.13.7-1),
readline-common (= 8.2-6),
rpcsvc-proto (= 1.4.3-1),
sed (= 4.9-2),
sensible-utils (= 0.0.24),
sysvinit-utils (= 3.13-1devuan1),
tar (= 1.35+dfsg-3.1),
tzdata (= 2024b-5),
util-linux (= 2.40.2-14devuan1),
xz-utils (= 5.6.3-1+b1),
zlib1g (= 1:1.3.dfsg+really1.3.1-1+b1)
Environment:
DEB_BUILD_OPTIONS="parallel=8"
LANG="en_ZA.UTF-8"
SOURCE_DATE_EPOCH="1757827219"
......@@ -560,7 +560,7 @@ async def main():
parser = argparse.ArgumentParser(description='WebSocket SSH Daemon (wssshd)')
parser.add_argument('--config', help='Configuration file path (default: /etc/wssshd.conf)')
parser.add_argument('--host', help='WebSocket server host')
parser.add_argument('--port', type=int, help='WebSocket server port')
parser.add_argument('--port', type=int, default=9898, help='WebSocket server port (default: 9898)')
parser.add_argument('--domain', help='Base domain name')
parser.add_argument('--password', help='Registration password')
parser.add_argument('--web-host', help='Web interface host (optional)')
......@@ -606,8 +606,6 @@ async def main():
# Check required arguments
if not args.host:
parser.error('--host is required')
if not args.port:
parser.error('--port is required')
if not args.domain:
parser.error('--domain is required')
if not args.password:
......@@ -667,7 +665,7 @@ async def main():
# Generate self-signed certificate if it doesn't exist
if not os.path.exists(web_cert_path) or not os.path.exists(web_key_path):
print("Generating self-signed certificate for web interface...")
os.system(f'openssl req -x509 -newkey rsa:4096 -keyout {web_key_path} -out {web_cert_path} -days 365 -nodes -subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"')
os.system(f'openssl req -x509 -newkey rsa:4096 -keyout {web_key_path} -out {web_cert_path} -days 36500 -nodes -subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"')
ssl_context = (web_cert_path, web_key_path)
......
......@@ -56,6 +56,8 @@ CFLAGS = -Wall -Wextra -O2 $(shell pkg-config --cflags openssl)
LDFLAGS = $(shell pkg-config --libs openssl)
# Source files
LIB_SRCS = wssshlib.c websocket.c wssh_ssl.c tunnel.c
LIB_OBJS = $(LIB_SRCS:.c=.o)
SRCS = wssshc.c wsssh.c wsscp.c
OBJS = $(SRCS:.c=.o)
TARGETS = wssshc wsssh wsscp
......@@ -67,13 +69,13 @@ MANPAGES = man/wssshc.1 man/wsssh.1 man/wsscp.1
all: $(TARGETS)
# Individual targets
wssshc: wssshc.o
wssshc: wssshc.o $(LIB_OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
wsssh: wsssh.o
wsssh: wsssh.o $(LIB_OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
wsscp: wsscp.o
wsscp: wsscp.o $(LIB_OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
# Object files
......@@ -82,7 +84,7 @@ wsscp: wsscp.o
# Clean
clean:
rm -f $(OBJS) $(TARGETS)
rm -f $(OBJS) $(LIB_OBJS) $(TARGETS)
# Install (optional)
install: all
......
......@@ -26,8 +26,8 @@ Display help message and exit
Hostnames in source/destination paths follow the format: [\fIuser\fR@]\fIclient_id\fR.\fIwssshd_host\fR[:\fIport\fR]
.TP
Examples:
- \fBuser@remote.example.com:/path/file\fR → client: \fBremote\fR, server: \fBexample.com:22\fR
- \fBserver.datacenter.com:9898/file\fR → client: \fBserver\fR, server: \fBdatacenter.com:9898\fR
- \fBuser@remote.example.com:/path/file\fR → client: \fBremote\fR, server: \fBexample.com:9898\fR
- \fBserver.datacenter.com:2222/file\fR → client: \fBserver\fR, server: \fBdatacenter.com:2222\fR
.SH EXAMPLES
.TP
Copy file to remote:
......
......@@ -25,8 +25,8 @@ Display help message and exit
The hostname follows the format: \fIclient_id\fR.\fIwssshd_host\fR[:\fIport\fR]
.TP
Examples:
- \fBremote.example.com\fR → client: \fBremote\fR, server: \fBexample.com:22\fR
- \fBserver.datacenter.com:9898\fR → client: \fBserver\fR, server: \fBdatacenter.com:9898\fR
- \fBremote.example.com\fR → client: \fBremote\fR, server: \fBexample.com:9898\fR
- \fBserver.datacenter.com:2222\fR → client: \fBserver\fR, server: \fBdatacenter.com:2222\fR
.SH EXAMPLES
.TP
Basic SSH connection:
......
This diff is collapsed.
/*
* WebSocket SSH Library - Tunnel management
*
* 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/>.
*/
#ifndef TUNNEL_H
#define TUNNEL_H
#include <openssl/ssl.h>
#include <pthread.h>
// Frame buffer for wsscp
typedef struct {
char *buffer;
size_t size;
size_t used;
} frame_buffer_t;
// Tunnel structure
typedef struct {
int local_sock; // Local TCP connection socket
int sock; // Alternative socket member for wssshc compatibility
char request_id[37]; // UUID string
int active;
SSL *ssl; // WebSocket SSL connection
frame_buffer_t *outgoing_buffer; // Buffer for data to send to local socket (wsscp only)
} tunnel_t;
// Global variables
extern tunnel_t *active_tunnel;
extern pthread_mutex_t tunnel_mutex;
// Function declarations
frame_buffer_t *frame_buffer_init(void);
void frame_buffer_free(frame_buffer_t *fb);
int frame_buffer_resize(frame_buffer_t *fb, size_t new_size);
int frame_buffer_append(frame_buffer_t *fb, const char *data, size_t len);
int frame_buffer_consume(frame_buffer_t *fb, size_t len);
void *forward_tcp_to_ws(void *arg);
void *tunnel_thread(void *arg);
void handle_tunnel_request(SSL *ssl, const char *request_id, int debug);
void handle_tunnel_data(SSL *ssl, const char *request_id, const char *data_hex, int debug);
void handle_tunnel_close(SSL *ssl, const char *request_id, int debug);
void cleanup_tunnel(int debug);
int reconnect_websocket(tunnel_t *tunnel, const char *wssshd_host, int wssshd_port, const char *client_id, const char *request_id, int debug);
int setup_tunnel(const char *wssshd_host, int wssshd_port, const char *client_id, int local_port, int debug, int use_buffer);
#endif // TUNNEL_H
\ No newline at end of file
/*
* WebSocket SSH Library - WebSocket functions implementation
*
* 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/>.
*/
#include "websocket.h"
#include "wssshlib.h"
#include <openssl/err.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int websocket_handshake(SSL *ssl, const char *host, int port, const char *path) {
char request[1024];
char response[BUFFER_SIZE];
int bytes_read;
// Send WebSocket handshake
snprintf(request, sizeof(request),
"GET %s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Upgrade: websocket\r\n"
"Connection: upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n",
path, host, port);
if (SSL_write(ssl, request, strlen(request)) <= 0) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "WebSocket handshake send failed\n");
return 0;
}
// Read response
bytes_read = SSL_read(ssl, response, sizeof(response) - 1);
if (bytes_read <= 0) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "WebSocket handshake recv failed\n");
return 0;
}
response[bytes_read] = '\0';
// Check for successful handshake
if (strstr(response, "101 Switching Protocols") == NULL) {
fprintf(stderr, "WebSocket handshake failed\n");
return 0;
}
return 1;
}
int send_json_message(SSL *ssl, const char *type, const char *client_id, const char *request_id) {
char message[1024];
if (request_id) {
snprintf(message, sizeof(message),
"{\"type\":\"%s\",\"client_id\":\"%s\",\"request_id\":\"%s\"}",
type, client_id, request_id);
} else {
snprintf(message, sizeof(message),
"{\"type\":\"%s\",\"client_id\":\"%s\"}",
type, client_id);
}
// Send as WebSocket frame
return send_websocket_frame(ssl, message);
}
int send_websocket_frame(SSL *ssl, const char *data) {
char frame[BUFFER_SIZE];
frame[0] = 0x81; // FIN + text opcode
int msg_len = strlen(data);
int header_len = 2;
if (msg_len <= 125) {
frame[1] = 0x80 | msg_len; // MASK + length
} else if (msg_len <= 65535) {
frame[1] = 0x80 | 126; // MASK + extended length
frame[2] = (msg_len >> 8) & 0xFF;
frame[3] = msg_len & 0xFF;
header_len = 4;
} else {
frame[1] = 0x80 | 127; // MASK + extended length
frame[2] = 0;
frame[3] = 0;
frame[4] = 0;
frame[5] = 0;
frame[6] = (msg_len >> 24) & 0xFF;
frame[7] = (msg_len >> 16) & 0xFF;
frame[8] = (msg_len >> 8) & 0xFF;
frame[9] = msg_len & 0xFF;
header_len = 10;
}
// Add mask key
char mask_key[4];
for (int i = 0; i < 4; i++) {
mask_key[i] = rand() % 256;
frame[header_len + i] = mask_key[i];
}
header_len += 4;
// Mask payload
for (int i = 0; i < msg_len; i++) {
frame[header_len + i] = data[i] ^ mask_key[i % 4];
}
int frame_len = header_len + msg_len;
return SSL_write(ssl, frame, frame_len) > 0;
}
int send_pong_frame(SSL *ssl, const char *ping_payload, int payload_len) {
char frame[BUFFER_SIZE];
frame[0] = 0x8A; // FIN + pong opcode
int header_len = 2;
if (payload_len <= 125) {
frame[1] = 0x80 | payload_len; // MASK + length
} else if (payload_len <= 65535) {
frame[1] = 0x80 | 126; // MASK + extended length
frame[2] = (payload_len >> 8) & 0xFF;
frame[3] = payload_len & 0xFF;
header_len = 4;
} else {
frame[1] = 0x80 | 127; // MASK + extended length
frame[2] = 0;
frame[3] = 0;
frame[4] = 0;
frame[5] = 0;
frame[6] = (payload_len >> 24) & 0xFF;
frame[7] = (payload_len >> 16) & 0xFF;
frame[8] = (payload_len >> 8) & 0xFF;
frame[9] = payload_len & 0xFF;
header_len = 10;
}
// Add mask key
char mask_key[4];
for (int i = 0; i < 4; i++) {
mask_key[i] = rand() % 256;
frame[header_len + i] = mask_key[i];
}
header_len += 4;
// Mask payload
for (int i = 0; i < payload_len; i++) {
frame[header_len + i] = ping_payload[i] ^ mask_key[i % 4];
}
int frame_len = header_len + payload_len;
return SSL_write(ssl, frame, frame_len) > 0;
}
int parse_websocket_frame(const char *buffer, int bytes_read, char **payload, int *payload_len) {
if (bytes_read < 2) {
return 0; // Not enough data for a frame
}
unsigned char frame_type = buffer[0] & 0x8F;
if (frame_type != 0x81 && frame_type != 0x82 && frame_type != 0x88 && frame_type != 0x89 && frame_type != 0x8A) {
return 0; // Not a supported frame type (text, binary, close, ping, pong)
}
int masked = buffer[1] & 0x80;
int len_indicator = buffer[1] & 0x7F;
int header_len = 2;
if (len_indicator <= 125) {
*payload_len = len_indicator;
} else if (len_indicator == 126) {
if (bytes_read < 4) return 0;
*payload_len = ((unsigned char)buffer[2] << 8) | (unsigned char)buffer[3];
header_len = 4;
} else if (len_indicator == 127) {
if (bytes_read < 10) return 0;
unsigned long long full_len = ((unsigned long long)(unsigned char)buffer[2] << 56) |
((unsigned long long)(unsigned char)buffer[3] << 48) |
((unsigned long long)(unsigned char)buffer[4] << 40) |
((unsigned long long)(unsigned char)buffer[5] << 32) |
((unsigned long long)(unsigned char)buffer[6] << 24) |
((unsigned long long)(unsigned char)buffer[7] << 16) |
((unsigned long long)(unsigned char)buffer[8] << 8) |
(unsigned char)buffer[9];
if (full_len > INT_MAX) {
return 0; // Payload too large
}
*payload_len = (int)full_len;
header_len = 10;
} else {
// Invalid length indicator
return 0;
}
if (masked) {
header_len += 4;
}
if (bytes_read < header_len + *payload_len) {
return 0; // Incomplete frame
}
*payload = (char *)buffer + header_len;
if (masked) {
char *mask_key = (char *)buffer + header_len - 4;
for (int i = 0; i < *payload_len; i++) {
(*payload)[i] ^= mask_key[i % 4];
}
}
return 1;
}
\ No newline at end of file
/*
* WebSocket SSH Library - WebSocket functions
*
* 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/>.
*/
#ifndef WEBSOCKET_H
#define WEBSOCKET_H
#include <openssl/ssl.h>
// Function declarations
int websocket_handshake(SSL *ssl, const char *host, int port, const char *path);
int send_json_message(SSL *ssl, const char *type, const char *client_id, const char *request_id);
int send_websocket_frame(SSL *ssl, const char *data);
int send_pong_frame(SSL *ssl, const char *ping_payload, int payload_len);
int parse_websocket_frame(const char *buffer, int bytes_read, char **payload, int *payload_len);
#endif // WEBSOCKET_H
\ No newline at end of file
This diff is collapsed.
/*
* WebSocket SSH Library - SSL functions implementation
*
* 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/>.
*/
#include "wssh_ssl.h"
#include <openssl/err.h>
#include <stdio.h>
SSL_CTX *create_ssl_context(void) {
SSL_CTX *ssl_ctx;
// Initialize SSL
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ssl_ctx = SSL_CTX_new(TLS_client_method());
if (!ssl_ctx) {
ERR_print_errors_fp(stderr);
return NULL;
}
// Allow self-signed certificates
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
return ssl_ctx;
}
SSL *create_ssl_connection(SSL_CTX *ssl_ctx, int sock, int debug) {
SSL *ssl = SSL_new(ssl_ctx);
SSL_set_fd(ssl, sock);
if (debug) {
printf("[DEBUG] Establishing SSL connection...\n");
fflush(stdout);
}
if (SSL_connect(ssl) <= 0) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "SSL connection failed\n");
SSL_free(ssl);
return NULL;
}
if (debug) {
printf("[DEBUG] SSL connection established\n");
fflush(stdout);
}
return ssl;
}
\ No newline at end of file
/*
* WebSocket SSH Library - SSL functions
*
* 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/>.
*/
#ifndef WSSH_SSL_H
#define WSSH_SSL_H
#include <openssl/ssl.h>
// Function declarations
SSL_CTX *create_ssl_context(void);
SSL *create_ssl_connection(SSL_CTX *ssl_ctx, int sock, int debug);
#endif // WSSH_SSL_H
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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