Commit 47cea202 authored by nextime's avatar nextime

Add debian package

parent b9fd9942
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.0-1) unstable; urgency=medium
* New upstream release 1.4.0
* Add comprehensive man page for wssshd daemon
* Include wssshd.1 man page in package installation
* Enhanced documentation and usage examples
* Improved PyInstaller binary packaging
* Better integration with Debian packaging standards
-- Stefy Lanza <stefy@nexlab.net> Mon, 13 Sep 2025 19:21:00 +0200
\ No newline at end of file
wsssh-server_1.4.0-1_amd64.buildinfo net optional
wsssh-server_1.4.0-1_amd64.deb net optional
shlibs:Depends=libc6 (>= 2.14), zlib1g (>= 1:1.1.4)
misc:Depends=
misc:Pre-Depends=
/etc/default/wssshd
/etc/init.d/wssshd
Package: wsssh-server
Version: 1.4.0-1
Architecture: amd64
Maintainer: Stefy Lanza <stefy@nexlab.net>
Installed-Size: 26669
Depends: libc6 (>= 2.14), zlib1g (>= 1:1.1.4), python3, python3-websockets, python3-flask, python3-flask-login, python3-flask-sqlalchemy, python3-pty, adduser
Section: net
Priority: optional
Homepage: https://github.com/stefy/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.
.
The wssshd server provides:
- WebSocket SSH tunnel management
- Client registration and authentication
- Web-based management interface
- Secure tunnel establishment between clients and servers
.
This is the server component of the WebSocket SSH system.
6a3b5dec71b2fc2a3caadae0845c256b usr/bin/wssshd
b800f3b9fa5614789d09ad78b5d0cced usr/share/doc/wsssh-server/changelog.Debian.gz
929c14c9c965f9fca6385eb474c66835 usr/share/doc/wsssh-server/copyright
209d40441e0a0779cebaa953c972d048 usr/share/man/man1/wssshd.1.gz
9e0b4abb77569710a6154f6f93fa8722 usr/share/wsssh/logos/banner-800x200.png
fbae8873c0f4be974ba0710a4431e55c usr/share/wsssh/logos/favicon.ico
4c6aa6b3da778593cc3d956c8f7cafe2 usr/share/wsssh/logos/icon-128.png
5e40d7476bd8f1a3d3ad5db912c78594 usr/share/wsssh/logos/icon-16.png
becc543efaf23e923c991109e8a88fcb usr/share/wsssh/logos/icon-256.png
19690beb1504df7b17b06db09f44ec8a usr/share/wsssh/logos/icon-32.png
1d52a67827d5c1fd7bca4093cc2879c0 usr/share/wsssh/logos/icon-48.png
72080ddcf42942d827e86c29839b82dc usr/share/wsssh/logos/icon-64.png
4c6aa6b3da778593cc3d956c8f7cafe2 usr/share/wsssh/logos/logo-128.png
becc543efaf23e923c991109e8a88fcb usr/share/wsssh/logos/logo-256.png
29ee9b99471d7e9135eb20e746df21fd usr/share/wsssh/logos/logo-512.png
72080ddcf42942d827e86c29839b82dc usr/share/wsssh/logos/logo-64.png
bd58776dc9820c39a46fd51316461fe2 usr/share/wsssh/logos/logo-high-quality.png
23e0c6c2fa6f1b0eb19321fce08a6607 usr/share/wsssh/templates/base.html
b98475a970285d499246a8627535a4cf usr/share/wsssh/templates/index.html
dd0dcf5219c6ab94aba6ca0da3186e1e usr/share/wsssh/templates/login.html
07c4c32362826d12c3a75b20b0c9a136 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
chown wssshd:wssshd /var/lib/wssshd
chmod 755 /var/lib/wssshd
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
# 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
;;
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.
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.
exit 0
\ 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
. /etc/rc.d/init.d/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 watchdog is already running
if [ -f "$WATCHDOG_PIDFILE" ]; then
local watchdog_pid=$(cat "$WATCHDOG_PIDFILE")
if kill -0 "$watchdog_pid" 2>/dev/null; then
echo -n "already running (watchdog PID: $watchdog_pid)"
echo_success
echo
return 0
else
# Stale watchdog PID file
rm -f "$WATCHDOG_PIDFILE"
fi
fi
# Check if config file exists
if [ ! -f "$CONFIG" ]; then
echo -n "configuration file $CONFIG not found"
echo_failure
echo
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 -n "daemon executable $DAEMON not found or not executable"
echo_failure
echo
return 1
fi
# Check if watchdog script exists
if [ ! -x "$WATCHDOG" ]; then
echo -n "watchdog script $WATCHDOG not found or not executable"
echo_failure
echo
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 watchdog (which will start and monitor the daemon)
$WATCHDOG start >/dev/null 2>&1
local retval=$?
if [ $retval -eq 0 ]; then
# Wait a moment for the watchdog to start
sleep 3
# Check if watchdog is running
if [ -f "$WATCHDOG_PIDFILE" ] && kill -0 "$(cat "$WATCHDOG_PIDFILE")" 2>/dev/null; then
echo_success
echo
return 0
else
echo_failure
echo
echo "Watchdog failed to start properly"
return 1
fi
else
echo_failure
echo
return $retval
fi
}
# Function to stop the daemon
stop() {
echo -n $"Stopping $NAME: "
# Check if watchdog is running
if [ ! -f "$WATCHDOG_PIDFILE" ]; then
echo -n "not running"
echo_success
echo
return 0
fi
# Stop the watchdog (which will stop the daemon)
$WATCHDOG stop >/dev/null 2>&1
local retval=$?
if [ $retval -eq 0 ]; then
# Wait a moment for everything to stop
sleep 3
# Clean up PID files
rm -f "$PIDFILE" "$WATCHDOG_PIDFILE"
echo_success
echo
return 0
else
echo_failure
echo
return $retval
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 -n "not running"
echo_failure
echo
return 1
fi
local pid=$(cat "$PIDFILE")
kill -HUP $pid 2>/dev/null
if [ $? -eq 0 ]; then
echo_success
echo
return 0
else
echo_failure
echo
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
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">
<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;
padding: 20px;
border-radius: 8px;
height: 600px;
overflow-y: auto;
}
.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="#">
<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">
<h3 class="card-title mb-0">
<i class="fas fa-terminal"></i> SSH Terminal - {{ client_id }}
</h3>
<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-0">
<div id="terminal" class="terminal-container"></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
});
term.open(document.getElementById('terminal'));
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;
// Send connect request
fetch('/terminal/{{ client_id }}/connect', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'username=' + encodeURIComponent(username)
})
.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 - let SSH server handle echoing
term.onData(data => {
if (!connected || !requestId) return;
// Send data to server
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) {
// Ensure proper line ending handling
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-tools
Binary: wsssh-tools wsssh-tools-dbgsym
Architecture: amd64 source
Version: 1.3.4-1
Checksums-Md5:
38c067ea3480c3fbeff48053919c3bfd 693 wsssh-tools_1.3.4-1.dsc
4b57871694a0f69f8fcf776851bf0abc 5160 wsssh-tools-dbgsym_1.3.4-1_amd64.deb
3c3fc6dbb344b8190de93efa16073439 33760 wsssh-tools_1.3.4-1_amd64.deb
Checksums-Sha1:
ac9b818083520befe49f980a323709ede9d3b1d2 693 wsssh-tools_1.3.4-1.dsc
e15b2f6c2ffe692612c76516ac8dd243a8f8aa30 5160 wsssh-tools-dbgsym_1.3.4-1_amd64.deb
70205ef8cfa84d5ca331b538365176d7d1c5025f 33760 wsssh-tools_1.3.4-1_amd64.deb
Checksums-Sha256:
d858604594098204fea793f24a5e8de3752a14b524fb26ea503aeb8c6432f11d 693 wsssh-tools_1.3.4-1.dsc
9d670374777af4fd63a25a9618f84561e41af658b2d9c1034e85faebe7c66849 5160 wsssh-tools-dbgsym_1.3.4-1_amd64.deb
e801605f8a19d0a8a7f9434db41402e2877fa4ca6572d939bd59118094309779 33760 wsssh-tools_1.3.4-1_amd64.deb
Build-Origin: Devuan
Build-Architecture: amd64
Build-Date: Sat, 13 Sep 2025 20:34:38 +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),
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),
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),
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),
libpkgconf3 (= 1.8.1-4),
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),
libssl-dev (= 3.4.0-2),
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),
ncurses-base (= 6.5-2),
ncurses-bin (= 6.5-2+b1),
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),
pkg-config (= 1.8.1-4),
pkgconf (= 1.8.1-4),
pkgconf-bin (= 1.8.1-4),
po-debconf (= 1.0.21+nmu1),
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),
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="1757773800"
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