Update Debian packages for embedded templates

- Remove template copying from wsssh-server package since templates are now embedded in wssshd2 binary
- Fix erroneous wssshd.py installation in wssshtools package
- Update both package changelogs to version 1.7.0-1
parent 90cc0568
wsssh-server (1.7.0-1) unstable; urgency=medium
* Version 1.7.0: Templates embedded in server binary
* Removed template copying from Debian package installation
* Templates now embedded in wssshd2 binary, eliminating external dependencies
* Updated package to reflect embedded web interface assets
-- Stefy Lanza <stefy@nexlab.net> Sun, 21 Sep 2025 17:42:00 +0200
wsssh-server (1.6.5-1) unstable; urgency=medium
* Version 1.6.5: Transition to C binary with SQLite database
* Complete rewrite from Python/PyInstaller to native C implementation
* Added SQLite database for persistent user management
* Implemented embedded web interface with user authentication
* Added comprehensive user management (add/edit/delete users)
* Security warning system for default admin credentials
* ASCII art banner on startup
* Improved performance with native C binary (no Python dependencies)
* Updated build system to use GCC instead of PyInstaller
* Added libsqlite3 and libssl runtime dependencies
* Updated man page with C version command line options
* Maintained all existing init scripts, logrotate, and service configurations
* Preserved backward compatibility for service management
* Enhanced security with proper session management
* Added debug options for database operations
-- Stefy Lanza <stefy@nexlab.net> Wed, 18 Sep 2025 08:47:00 +0200
wsssh-server (1.6.1-1) unstable; urgency=medium wsssh-server (1.6.1-1) unstable; urgency=medium
* Version 1.6.1: Major code refactoring and documentation updates * Version 1.6.1: Major code refactoring and documentation updates
......
wsssh-server (1.7.0-1) unstable; urgency=medium
* Version 1.7.0: Templates embedded in server binary
* Removed template copying from Debian package installation
* Templates now embedded in wssshd2 binary, eliminating external dependencies
* Updated package to reflect embedded web interface assets
-- Stefy Lanza <stefy@nexlab.net> Sun, 21 Sep 2025 17:42:00 +0200
wsssh-server (1.6.5-1) unstable; urgency=medium wsssh-server (1.6.5-1) unstable; urgency=medium
* Version 1.6.5: Transition to C binary with SQLite database * Version 1.6.5: Transition to C binary with SQLite database
......
...@@ -30,7 +30,6 @@ override_dh_auto_install: ...@@ -30,7 +30,6 @@ override_dh_auto_install:
mkdir -p debian/wsssh-server/etc/default/ mkdir -p debian/wsssh-server/etc/default/
mkdir -p debian/wsssh-server/usr/share/wsssh/ mkdir -p debian/wsssh-server/usr/share/wsssh/
mkdir -p debian/wsssh-server/usr/share/man/man1/ mkdir -p debian/wsssh-server/usr/share/man/man1/
mkdir -p debian/wsssh-server/usr/share/wsssh/templates
mkdir -p debian/wsssh-server/usr/share/wsssh/logos mkdir -p debian/wsssh-server/usr/share/wsssh/logos
mkdir -p debian/wsssh-server/var/lib/wssshd mkdir -p debian/wsssh-server/var/lib/wssshd
mkdir -p debian/wsssh-server/var/log/wssshd mkdir -p debian/wsssh-server/var/log/wssshd
...@@ -61,8 +60,7 @@ override_dh_auto_install: ...@@ -61,8 +60,7 @@ override_dh_auto_install:
mkdir -p debian/wsssh-server/lib/systemd/system mkdir -p debian/wsssh-server/lib/systemd/system
install -m 644 debian/wssshd.service debian/wsssh-server/lib/systemd/system/ install -m 644 debian/wssshd.service debian/wsssh-server/lib/systemd/system/
# Install web templates and static files # Install static files
cp -r ../templates/* debian/wsssh-server/usr/share/wsssh/templates/
cp -r ../logos/* debian/wsssh-server/usr/share/wsssh/logos/ cp -r ../logos/* debian/wsssh-server/usr/share/wsssh/logos/
override_dh_auto_clean: override_dh_auto_clean:
......
# Makefile for wssshd2 - Generated by configure.sh
# Do not edit manually, run ./configure.sh instead
CC = gcc
CFLAGS = -Wall -Wextra -O2 -I. -pthread
LDFLAGS = -lssl -lcrypto -lm -luuid -lsqlite3
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
MANDIR = $(PREFIX)/share/man
CONFIGDIR = /etc
# Source files
SRCS = main.c config.c tunnel.c terminal.c websocket.c websocket_protocol.c web.c assets.c ssl.c
OBJS = $(SRCS:.c=.o)
# Target
TARGET = wssshd
.PHONY: all clean install uninstall
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# Dependencies
main.o: main.c config.h websocket.h web.h
config.o: config.c config.h
tunnel.o: tunnel.c tunnel.h websocket.h
terminal.o: terminal.c terminal.h config.h
websocket.o: websocket.c websocket.h websocket_protocol.h config.h
websocket_protocol.o: websocket_protocol.c websocket_protocol.h
web.o: web.c web.h terminal.h assets.h websocket.h html_pages/index_page.h html_pages/login_page.h html_pages/terminal_page.h html_pages/users_page.h
assets.o: assets.c assets.h
ssl.o: ssl.c ssl.h
# Asset embedding (run before compilation)
assets.o: image_data.h
image_data.h: embed_assets.sh
./embed_assets.sh
clean:
rm -f $(OBJS) $(TARGET) image_data.h
install: $(TARGET)
install -d $(DESTDIR)$(BINDIR)
install -m 755 $(TARGET) $(DESTDIR)$(BINDIR)/
install -d $(DESTDIR)$(CONFIGDIR)
[ -f $(DESTDIR)$(CONFIGDIR)/wssshd.conf ] || install -m 644 wssshd.conf.example $(DESTDIR)$(CONFIGDIR)/wssshd.conf
install -d $(DESTDIR)$(MANDIR)/man8
install -m 644 wssshd.8 $(DESTDIR)$(MANDIR)/man8/
uninstall:
rm -f $(DESTDIR)$(BINDIR)/$(TARGET)
rm -f $(DESTDIR)$(MANDIR)/man8/wssshd.8
# Development targets
debug: CFLAGS += -g -DDEBUG
debug: clean all
test: $(TARGET)
@echo "Running basic functionality test..."
./$(TARGET) --help || true
distclean: clean
rm -f Makefile
# Help target
help:
@echo "Available targets:"
@echo " all - Build wssshd2 (default)"
@echo " clean - Remove build artifacts"
@echo " install - Install wssshd2 to system"
@echo " uninstall - Remove wssshd2 from system"
@echo " debug - Build with debug symbols"
@echo " test - Run basic tests"
@echo " distclean - Remove all generated files"
@echo " help - Show this help"
This source diff could not be displayed because it is too large. You can view the blob instead.
File added
File added
<!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="/image.jpg" 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://unpkg.com/xterm@5.3.0/css/xterm.css">
<script src="https://unpkg.com/xterm@5.3.0/lib/xterm.js"></script>
<script src="https://unpkg.com/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script>
<script>
// Ensure libraries are loaded
function checkLibraries() {
if (typeof Terminal === 'undefined') {
console.error('Terminal not loaded from CDN');
return false;
}
if (typeof FitAddon === 'undefined') {
console.error('FitAddon not loaded from CDN');
return false;
}
console.log('All xterm libraries loaded successfully');
return true;
}
// Check immediately and after a delay
if (!checkLibraries()) {
setTimeout(checkLibraries, 1000);
}
</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
This diff is collapsed.
{% 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
File added
File added
wsssh-tools (1.7.0-1) unstable; urgency=medium
* Version 1.7.0: Version synchronization with server component
* No functional changes - client tools remain compatible with embedded server
-- Stefy Lanza <stefy@nexlab.net> Sun, 21 Sep 2025 17:42:00 +0200
wsssh-tools (1.6.5-1) unstable; urgency=medium wsssh-tools (1.6.5-1) unstable; urgency=medium
* Version 1.6.5: Flexible data encoding support for wsssht * Version 1.6.5: Flexible data encoding support for wsssht
......
...@@ -63,9 +63,6 @@ override_dh_auto_install: ...@@ -63,9 +63,6 @@ override_dh_auto_install:
install -m 644 debian/wssshc.service debian/wsssh-tools/lib/systemd/system/ install -m 644 debian/wssshc.service debian/wsssh-tools/lib/systemd/system/
install -m 644 debian/wsssht.service debian/wsssh-tools/lib/systemd/system/ install -m 644 debian/wsssht.service debian/wsssh-tools/lib/systemd/system/
# Install Python scripts
install -m 755 ../wssshd.py debian/wsssh-tools/usr/bin/
override_dh_auto_clean: override_dh_auto_clean:
make clean make clean
rm -f configure.sh.stamp rm -f configure.sh.stamp
\ No newline at end of file
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