Fix xterm.js terminal issues: xterm256 support, data display, polling, debug logging, and crash fix

parent 9c8b37b9
# 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
# HTML page generation
html_pages/index_page.h html_pages/login_page.h html_pages/terminal_page.h: embed_assets.sh
./embed_assets.sh
clean:
rm -f $(OBJS) $(TARGET) image_data.h favicon_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 diff is collapsed.
This diff is collapsed.
/**
* index page HTML template for wssshd
*
* 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 INDEX_PAGE_H
#define INDEX_PAGE_H
// index page HTML template
static const char *index_page_html =
"<!DOCTYPE html>\n"
"<html lang=\"en\">\n"
"<head>\n"
" <meta charset=\"UTF-8\">\n"
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
" <title>Dashboard - WebSocket SSH Daemon</title>\n"
" <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\">\n"
" <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n"
" <link href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" rel=\"stylesheet\">\n"
"</head>\n"
"<body>\n"
"<nav class=\"navbar navbar-expand-lg navbar-dark bg-primary\">\n"
"<div class=\"container\">\n"
"<a class=\"navbar-brand\" href=\"/\">\n"
"<i class=\"fas fa-terminal\"></i> WebSocket SSH Daemon</a>\n"
"<div class=\"navbar-nav ms-auto\">\n"
"<span class=\"navbar-text me-3\">%s</span>\n"
"<a class=\"nav-link\" href=\"/logout\">Logout</a>\n"
"</div></div></nav>\n"
"%s\n"
"<div class=\"container mt-4\">\n"
"<div class=\"row\">\n"
" <div class=\"col-md-8\">\n"
" <div class=\"card\">\n"
" <div class=\"card-header\">\n"
" <h3 class=\"card-title mb-0\">\n"
" <i class=\"fas fa-server\"></i> Registered Clients\n"
" </h3>\n"
" </div>\n"
" <div class=\"card-body\">\n"
" <div id=\"client-list\">%s</div>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"\n"
" <div class=\"col-md-4\">\n"
" <div class=\"card\">\n"
" <div class=\"card-header\">\n"
" <h3 class=\"card-title mb-0\">\n"
" <i class=\"fas fa-cogs\"></i> Quick Actions\n"
" </h3>\n"
" </div>\n"
" <div class=\"card-body\">\n"
" %s\n"
" <button class=\"btn btn-outline-secondary btn-sm w-100\" onclick=\"location.reload()\">\n"
" <i class=\"fas fa-sync\"></i> Refresh Status\n"
" </button>\n"
" </div>\n"
" </div>\n"
"\n"
" <div class=\"card mt-3\">\n"
" <div class=\"card-header\">\n"
" <h3 class=\"card-title mb-0\">\n"
" <i class=\"fas fa-info-circle\"></i> System Info\n"
" </h3>\n"
" </div>\n"
" <div class=\"card-body\">\n"
" <p class=\"mb-1\"><strong>WebSocket Port:</strong> <span id=\"websocket-port\">%d</span></p>\n"
" <p class=\"mb-1\"><strong>Domain:</strong> <span id=\"domain\">%s</span></p>\n"
" <p class=\"mb-0\"><strong>Connected Clients:</strong> <span id=\"client-count\">%d</span></p>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"</div>\n"
"<script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js\"></script>\n"
"<script>\n"
"function showNotification(message, type = 'info') {\n"
" const notificationArea = document.getElementById('notification-area');\n"
" const notification = document.createElement('div');\n"
" notification.className = `alert alert-${type} alert-dismissible fade show`;\n"
" notification.innerHTML = `${message}<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\"></button>`;\n"
" notificationArea.appendChild(notification);\n"
" setTimeout(() => {\n"
" if (notification.parentNode) {\n"
" notification.remove();\n"
" }\n"
" }, 5000);\n"
"}\n"
"\n"
"function updateClients() {\n"
" fetch('/api/clients')\n"
" .then(response => response.json())\n"
" .then(data => {\n"
" // Update client count\n"
" document.getElementById('client-count').textContent = data.count;\n"
"\n"
" // Generate HTML for client list\n"
" let clientListHtml = '';\n"
" if (data.count === 0) {\n"
" clientListHtml = '<div class=\"text-center py-5\"><i class=\"fas fa-server fa-4x text-muted mb-3\"></i><h4 class=\"text-muted\">No clients registered</h4><p class=\"text-muted\">Clients will appear here when they register.</p></div>';\n"
" } else {\n"
" for (const [clientId, clientData] of Object.entries(data.clients)) {\n"
" const statusIcon = clientData.status === 'connected' ? 'fa-desktop text-success' : 'fa-server text-warning';\n"
" const statusText = clientData.status === 'connected' ? 'Connected' : 'Registered';\n"
" const services = clientData.services;\n"
" let actionsHtml = '';\n"
" if (services.includes('ssh')) {\n"
" actionsHtml += `<a href=\"/terminal/${clientId}\" class=\"btn btn-primary btn-sm me-1\"><i class=\"fas fa-terminal\"></i> SSH</a>`;\n"
" }\n"
" // Add other services if needed\n"
" clientListHtml += `\n"
" <div class=\"col-md-4 mb-3\">\n"
" <div class=\"card client-card h-100\">\n"
" <div class=\"card-body text-center\">\n"
" <i class=\"fas ${statusIcon} fa-3x mb-3\"></i>\n"
" <h5 class=\"card-title\">${clientId}</h5>\n"
" <p class=\"card-text text-muted\">${statusText}</p>\n"
" <p class=\"card-text small\">Services: ${services}</p>\n"
" <div class=\"d-flex justify-content-center\">${actionsHtml}</div>\n"
" </div>\n"
" </div>\n"
" </div>`;\n"
" }\n"
" }\n"
"\n"
" // Update client list only if changed\n"
" const clientListDiv = document.getElementById('client-list');\n"
" if (clientListDiv.innerHTML !== clientListHtml) {\n"
" clientListDiv.innerHTML = clientListHtml;\n"
" }\n"
" })\n"
" .catch(error => {\n"
" console.log('Error fetching client data:', error);\n"
" });\n"
"}\n"
"\n"
"// Update every 5 seconds\n"
"setInterval(updateClients, 5000);\n"
"\n"
"// Initial update after 1 second\n"
"setTimeout(updateClients, 1000);\n"
"</script>\n"
"</body>\n"
"</html>\n";
#endif /* INDEX_PAGE_H */
/**
* login page HTML template for wssshd
*
* 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 LOGIN_PAGE_H
#define LOGIN_PAGE_H
// login page HTML template
static const char *login_page_html =
"<!DOCTYPE html>\n"
"<html lang=\"en\">\n"
"<head>\n"
" <meta charset=\"UTF-8\">\n"
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
" <title>Login - WebSocket SSH Daemon</title>\n"
" <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\">\n"
" <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n"
" <link href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" rel=\"stylesheet\">\n"
"</head>\n"
"<body>\n"
"<nav class=\"navbar navbar-expand-lg navbar-dark bg-primary\">\n"
"<div class=\"container\">\n"
"<a class=\"navbar-brand\" href=\"/\">\n"
"<i class=\"fas fa-terminal\"></i> WebSocket SSH Daemon</a>\n"
"</div></nav>\n"
"<div class=\"container mt-4\">\n"
"<div class=\"row justify-content-center\">\n"
" <div class=\"col-md-6\">\n"
" <div class=\"card\">\n"
" <div class=\"card-header\">\n"
" <h3 class=\"card-title mb-0\"><i class=\"fas fa-sign-in-alt\"></i> Login</h3>\n"
" </div>\n"
" <div class=\"card-body\">\n"
" <form method=\"post\">\n"
" <div class=\"mb-3\">\n"
" <label for=\"username\" class=\"form-label\">Username</label>\n"
" <input type=\"text\" class=\"form-control\" id=\"username\" name=\"username\" required>\n"
" </div>\n"
" <div class=\"mb-3\">\n"
" <label for=\"password\" class=\"form-label\">Password</label>\n"
" <input type=\"password\" class=\"form-control\" id=\"password\" name=\"password\" required>\n"
" </div>\n"
" <button type=\"submit\" class=\"btn btn-primary\">\n"
" <i class=\"fas fa-sign-in-alt\"></i> Login\n"
" </button>\n"
" </form>\n"
" <div class=\"mt-3\">\n"
" <small class=\"text-muted\">\n"
" Default credentials: admin / admin123\n"
" </small>\n"
" </div>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"</div>\n"
"<script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js\"></script>\n"
"</body>\n"
"</html>\n";
#endif /* LOGIN_PAGE_H */
This diff is collapsed.
/**
* users page HTML template for wssshd
*
* 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 USERS_PAGE_H
#define USERS_PAGE_H
// users page HTML template
static const char *users_page_html =
"<!DOCTYPE html>\n"
"<html lang=\"en\">\n"
"<head>\n"
" <meta charset=\"UTF-8\">\n"
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
" <title>Users - WebSocket SSH Daemon</title>\n"
" <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\">\n"
" <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n"
" <link href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" rel=\"stylesheet\">\n"
"</head>\n"
"<body>\n"
"<nav class=\"navbar navbar-expand-lg navbar-dark bg-primary\">\n"
"<div class=\"container\">\n"
"<a class=\"navbar-brand\" href=\"/\">\n"
"<i class=\"fas fa-terminal\"></i> WebSocket SSH Daemon</a>\n"
"<div class=\"navbar-nav ms-auto\">\n"
"<span class=\"navbar-text me-3\">%s</span>\n"
"<a class=\"nav-link\" href=\"/logout\">Logout</a>\n"
"</div></div></nav>\n"
"<div class=\"container mt-4\">\n"
" <div class=\"card\">\n"
" <div class=\"card-header d-flex justify-content-between align-items-center\">\n"
" <h3 class=\"card-title mb-0\">\n"
" <i class=\"fas fa-users\"></i> User Management\n"
" </h3>\n"
" <div>\n"
" <a href=\"/\" class=\"btn btn-outline-secondary btn-sm me-2\">\n"
" <i class=\"fas fa-home\"></i> Back to Home\n"
" </a>\n"
" <button class=\"btn btn-primary btn-sm\" data-bs-toggle=\"modal\" data-bs-target=\"#addUserModal\">\n"
" <i class=\"fas fa-plus\"></i> Add User\n"
" </button>\n"
" </div>\n"
" </div>\n"
" <div class=\"card-body\">\n"
" <div class=\"table-responsive\">\n"
" <table class=\"table table-striped\">\n"
" <thead>\n"
" <tr>\n"
" <th>Username</th>\n"
" <th>Role</th>\n"
" <th>Actions</th>\n"
" </tr>\n"
" </thead>\n"
" <tbody>\n"
" %s\n"
" </tbody>\n"
" </table>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"\n"
"<!-- Add User Modal -->\n"
"<div class=\"modal fade\" id=\"addUserModal\" tabindex=\"-1\">\n"
" <div class=\"modal-dialog\">\n"
" <div class=\"modal-content\">\n"
" <div class=\"modal-header\">\n"
" <h5 class=\"modal-title\">Add New User</h5>\n"
" <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button>\n"
" </div>\n"
" <form id=\"addUserForm\">\n"
" <div class=\"modal-body\">\n"
" <div class=\"mb-3\">\n"
" <label for=\"addUsername\" class=\"form-label\">Username</label>\n"
" <input type=\"text\" class=\"form-control\" id=\"addUsername\" name=\"username\" required>\n"
" </div>\n"
" <div class=\"mb-3\">\n"
" <label for=\"addPassword\" class=\"form-label\">Password</label>\n"
" <input type=\"password\" class=\"form-control\" id=\"addPassword\" name=\"password\" required>\n"
" </div>\n"
" <div class=\"mb-3 form-check\">\n"
" <input type=\"checkbox\" class=\"form-check-input\" id=\"addIsAdmin\" name=\"is_admin\">\n"
" <label class=\"form-check-label\" for=\"addIsAdmin\">Administrator</label>\n"
" </div>\n"
" </div>\n"
" <div class=\"modal-footer\">\n"
" <button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button>\n"
" <button type=\"submit\" class=\"btn btn-primary\">Add User</button>\n"
" </div>\n"
" </form>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"\n"
"<!-- Edit User Modal -->\n"
"<div class=\"modal fade\" id=\"editUserModal\" tabindex=\"-1\">\n"
" <div class=\"modal-dialog\">\n"
" <div class=\"modal-content\">\n"
" <div class=\"modal-header\">\n"
" <h5 class=\"modal-title\">Edit User</h5>\n"
" <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button>\n"
" </div>\n"
" <form id=\"editUserForm\">\n"
" <input type=\"hidden\" id=\"editUserId\" name=\"user_id\">\n"
" <div class=\"modal-body\">\n"
" <div class=\"mb-3\">\n"
" <label for=\"editUsername\" class=\"form-label\">Username</label>\n"
" <input type=\"text\" class=\"form-control\" id=\"editUsername\" name=\"username\" required>\n"
" </div>\n"
" <div class=\"mb-3\">\n"
" <label for=\"editPassword\" class=\"form-label\">New Password (leave empty to keep current)</label>\n"
" <input type=\"password\" class=\"form-control\" id=\"editPassword\" name=\"password\">\n"
" </div>\n"
" <div class=\"mb-3 form-check\">\n"
" <input type=\"checkbox\" class=\"form-check-input\" id=\"editIsAdmin\" name=\"is_admin\">\n"
" <label class=\"form-check-label\" for=\"editIsAdmin\">Administrator</label>\n"
" </div>\n"
" </div>\n"
" <div class=\"modal-footer\">\n"
" <button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button>\n"
" <button type=\"submit\" class=\"btn btn-primary\">Update User</button>\n"
" </div>\n"
" </form>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"\n"
"<script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js\"></script>\n"
"<script>\n"
"function editUser(userId, username, isAdmin) {\n"
" document.getElementById('editUserId').value = userId;\n"
" document.getElementById('editUsername').value = username;\n"
" document.getElementById('editPassword').value = '';\n"
" document.getElementById('editIsAdmin').checked = isAdmin;\n"
" new bootstrap.Modal(document.getElementById('editUserModal')).show();\n"
"}\n"
"\n"
"function deleteUser(userId, username) {\n"
" if (confirm(`Are you sure you want to delete user \"${username}\"?`)) {\n"
" fetch(`/delete_user/${userId}`, {\n"
" method: 'POST',\n"
" headers: {'Content-Type': 'application/x-www-form-urlencoded'}\n"
" })\n"
" .then(response => response.json())\n"
" .then(data => {\n"
" if (data.success) location.reload();\n"
" else alert('Error: ' + data.error);\n"
" });\n"
" }\n"
"}\n"
"\n"
"document.getElementById('addUserForm').addEventListener('submit', function(e) {\n"
" e.preventDefault();\n"
" const formData = new FormData(this);\n"
" fetch('/add_user', {method: 'POST', body: formData})\n"
" .then(response => response.json())\n"
" .then(data => {\n"
" if (data.success) {\n"
" bootstrap.Modal.getInstance(document.getElementById('addUserModal')).hide();\n"
" location.reload();\n"
" } else alert('Error: ' + data.error);\n"
" });\n"
"});\n"
"\n"
"document.getElementById('editUserForm').addEventListener('submit', function(e) {\n"
" e.preventDefault();\n"
" const formData = new FormData(this);\n"
" const userId = document.getElementById('editUserId').value;\n"
" fetch(`/edit_user/${userId}`, {method: 'POST', body: formData})\n"
" .then(response => response.json())\n"
" .then(data => {\n"
" if (data.success) {\n"
" bootstrap.Modal.getInstance(document.getElementById('editUserModal')).hide();\n"
" location.reload();\n"
" } else alert('Error: ' + data.error);\n"
" });\n"
"});\n"
"</script>\n"
"</body>\n"
"</html>\n";
#endif /* USERS_PAGE_H */
/**
* xterm-addon-fit.js library for wssshd
*
* 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 XTERM_ADDON_PAGE_H
#define XTERM_ADDON_PAGE_H
// xterm-addon-fit.js library
const char *xterm_addon_fit_js =
"!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define([],t):\"object\"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(()=>(()=>{\"use strict\";var e={};return(()=>{var t=e;Object.defineProperty(t,\"__esModule\",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core,t=e._renderService.dimensions;if(0===t.css.cell.width||0===t.css.cell.height)return;const r=0===this._terminal.options.scrollback?0:e.viewport.scrollBarWidth,i=window.getComputedStyle(this._terminal.element.parentElement),o=parseInt(i.getPropertyValue(\"height\")),s=Math.max(0,parseInt(i.getPropertyValue(\"width\"))),n=window.getComputedStyle(this._terminal.element),l=o-(parseInt(n.getPropertyValue(\"padding-top\"))+parseInt(n.getPropertyValue(\"padding-bottom\"))),a=s-(parseInt(n.getPropertyValue(\"padding-right\"))+parseInt(n.getPropertyValue(\"padding-left\")))-r;return{cols:Math.max(2,Math.floor(a/t.css.cell.width)),rows:Math.max(1,Math.floor(l/t.css.cell.height))}}}})(),e})()));\n"
"//# sourceMappingURL=xterm-addon-fit.js.map\n";
#endif /* XTERM_ADDON_PAGE_H */
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
File added
File added
......@@ -354,10 +354,9 @@ function connect() {
console.log('Launching command:', data.command);
}
term.write('Connected successfully!\r\n');
setTimeout(() => {
pollInterval = setInterval(pollData, 100);
}, 100);
pollInterval = setInterval(pollData, 500);
// Poll immediately to get any buffered output
pollData();
} else {
term.write('Error: ' + (data.error || 'Unknown error') + '\r\n');
disconnect();
......@@ -419,7 +418,10 @@ function disconnect() {
}
if (term) {
term.write('\r\nDisconnected.\r\n');
term.write('\r\nDisconnect\r\n');
setTimeout(() => {
location.reload();
}, 3000);
}
}
......@@ -441,8 +443,10 @@ function pollData() {
console.log('Poll data received:', data);
if (data.ended !== undefined) {
console.log('Session ended, reloading page');
clearInterval(pollInterval);
pollInterval = null;
if (pollInterval) {
clearInterval(pollInterval);
pollInterval = null;
}
location.reload();
} else if (data) {
console.log('Received data:', data.byteLength || data.length, 'bytes/characters');
......
......@@ -354,10 +354,9 @@ function connect() {
console.log('Launching command:', data.command);
}
term.write('Connected successfully!\r\n');
setTimeout(() => {
pollInterval = setInterval(pollData, 100);
}, 100);
pollInterval = setInterval(pollData, 200);
}, 200);
} else {
term.write('Error: ' + (data.error || 'Unknown error') + '\r\n');
disconnect();
......@@ -374,13 +373,6 @@ function connect() {
if (!connected || !requestId) return;
let data = e.key;
if (data === 'Enter') {
data = '\r';
} else if (data === 'Backspace') {
data = '\b';
} else if (data === 'Tab') {
data = '\t';
}
console.log('Sending input data:', data);
// Send to server
......@@ -426,7 +418,10 @@ function disconnect() {
}
if (term) {
term.write('\r\nDisconnected.\r\n');
term.write('\r\nDisconnect\r\n');
setTimeout(() => {
location.reload();
}, 3000);
}
}
......
......@@ -175,7 +175,7 @@ terminal_session_t *terminal_create_session(const wssshd_config_t *config, const
close(slave_fd);
// Set environment
setenv("TERM", "xterm", 1);
setenv("TERM", "xterm-256color", 1);
setenv("COLUMNS", "80", 1);
setenv("LINES", "24", 1);
......
......@@ -586,7 +586,7 @@ static int parse_http_request(int client_fd, http_request_t *req) {
buffer[bytes_read] = '\0';
if (global_config && global_config->debug_web) {
if (global_config && global_config->debug_web && !strstr(req->path, "/xterm/data")) {
printf("[WEB-DEBUG] Raw buffer (%zd bytes): '", bytes_read);
for (ssize_t i = 0; i < bytes_read; i++) {
if (buffer[i] == '\r') printf("\\r");
......@@ -626,7 +626,7 @@ static int parse_http_request(int client_fd, http_request_t *req) {
content_length = atoi(cl_header);
}
if (global_config && global_config->debug_web) {
if (global_config && global_config->debug_web && !strstr(req->path, "/xterm/data")) {
printf("[WEB-DEBUG] Content-Length from header: %d\n", content_length);
}
......@@ -635,7 +635,7 @@ static int parse_http_request(int client_fd, http_request_t *req) {
char *body_start = NULL;
size_t body_length = 0;
if (global_config && global_config->debug_web) {
if (global_config && global_config->debug_web && !strstr(req->path, "/xterm/data")) {
printf("[WEB-DEBUG] Looking for body separator...\n");
}
......@@ -830,7 +830,7 @@ static const char *get_cookie(const char *headers, const char *name) {
static void send_response(int client_fd, int status_code, const char *status_text,
const char *content_type, const char *body, size_t body_len,
const char *set_cookie, const char *extra_header) {
if (global_config && global_config->debug_web) {
if (global_config && global_config->debug_web && strcmp(content_type, "application/octet-stream") != 0) {
printf("[WEB-DEBUG] Sending response: %d %s, Content-Type: %s, Length: %zu\n",
status_code, status_text, content_type, body_len);
if (set_cookie) {
......@@ -1019,7 +1019,7 @@ static void handle_request(int client_fd, const http_request_t *req) {
const char *username = NULL;
int is_admin = 0;
if (global_config && global_config->debug_web) {
if (global_config && global_config->debug_web && !strstr(req->path, "/xterm/data")) {
printf("[WEB-DEBUG] Session ID: %s\n", session_id ? session_id : "none");
}
......@@ -1031,7 +1031,7 @@ static void handle_request(int client_fd, const http_request_t *req) {
}
}
if (global_config && global_config->debug_web) {
if (global_config && global_config->debug_web && !strstr(req->path, "/xterm/data")) {
printf("[WEB-DEBUG] Authenticated user: %s (admin: %s)\n",
username ? username : "none", is_admin ? "yes" : "no");
}
......@@ -1055,7 +1055,7 @@ static void handle_request(int client_fd, const http_request_t *req) {
}
}
if (global_config && global_config->debug_web) {
if (global_config && global_config->debug_web && (!action || strcmp(action, "data") != 0)) {
printf("[WEB-DEBUG] Terminal request: path=%s, client_id=%s, action=%s\n", req->path, client_id, action ? action : "(null)");
}
......@@ -1119,7 +1119,7 @@ static void handle_request(int client_fd, const http_request_t *req) {
break;
}
}
if (global_config && global_config->debug_web) {
if (global_config && global_config->debug_web && strcmp(action, "data") != 0) {
printf("[WEB-DEBUG] Terminal action '%s' for client %s, client_exists=%d\n", action, client_id, client_exists);
}
if (!client_exists) {
......@@ -1341,11 +1341,12 @@ static void handle_request(int client_fd, const http_request_t *req) {
if (session_ended) {
send_response(client_fd, 200, "OK", "application/json; charset=utf-8", ended_json, sizeof(ended_json) - 1, NULL, NULL);
} else if (output) {
send_response(client_fd, 200, "OK", "text/plain; charset=utf-8", output, output_len, NULL, NULL);
send_response(client_fd, 200, "OK", "application/octet-stream", output, output_len, NULL, NULL);
free(output);
} else {
send_response(client_fd, 200, "OK", "text/plain; charset=utf-8", "", 0, NULL, NULL);
send_response(client_fd, 200, "OK", "application/octet-stream", "", 0, NULL, NULL);
}
// Skip debug for data responses to avoid spam
} else {
send_response(client_fd, 404, "Not Found", "text/plain", "Not found", 9, NULL, NULL);
}
......
File added
File added
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