diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index d23030df..2ee22c08 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -21,6 +21,8 @@ services: PORT: "4300" ENABLE_SSL: "true" SSL_DOMAIN: "termix-dev.karmaa.site" + SSL_CERT_PATH: "/app/data/ssl/termix.crt" + SSL_KEY_PATH: "/app/data/ssl/termix.key" # Resource limits for better large file handling deploy: resources: diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 9c50ab08..28a0b842 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -4,8 +4,8 @@ set -e export PORT=${PORT:-8080} export ENABLE_SSL=${ENABLE_SSL:-false} export SSL_PORT=${SSL_PORT:-8443} -export SSL_CERT_PATH=${SSL_CERT_PATH:-/app/ssl/termix.crt} -export SSL_KEY_PATH=${SSL_KEY_PATH:-/app/ssl/termix.key} +export SSL_CERT_PATH=${SSL_CERT_PATH:-/app/data/ssl/termix.crt} +export SSL_KEY_PATH=${SSL_KEY_PATH:-/app/data/ssl/termix.key} echo "Configuring web UI to run on port: $PORT" @@ -30,16 +30,16 @@ chmod 755 /app/data # If SSL is enabled, generate certificates first if [ "$ENABLE_SSL" = "true" ]; then echo "Generating SSL certificates..." - mkdir -p /app/ssl - chown -R node:node /app/ssl - chmod 755 /app/ssl + mkdir -p /app/data/ssl + chown -R node:node /app/data/ssl + chmod 755 /app/data/ssl # Generate SSL certificates using OpenSSL directly (faster and more reliable) DOMAIN=${SSL_DOMAIN:-localhost} echo "Generating certificate for domain: $DOMAIN" # Create OpenSSL config - cat > /app/ssl/openssl.conf << EOF + cat > /app/data/ssl/openssl.conf << EOF [req] default_bits = 2048 prompt = no @@ -69,18 +69,18 @@ IP.2 = ::1 EOF # Generate private key - openssl genrsa -out /app/ssl/termix.key 2048 + openssl genrsa -out /app/data/ssl/termix.key 2048 # Generate certificate - openssl req -new -x509 -key /app/ssl/termix.key -out /app/ssl/termix.crt -days 365 -config /app/ssl/openssl.conf -extensions v3_req + openssl req -new -x509 -key /app/data/ssl/termix.key -out /app/data/ssl/termix.crt -days 365 -config /app/data/ssl/openssl.conf -extensions v3_req # Set proper permissions - chmod 600 /app/ssl/termix.key - chmod 644 /app/ssl/termix.crt - chown node:node /app/ssl/termix.key /app/ssl/termix.crt + chmod 600 /app/data/ssl/termix.key + chmod 644 /app/data/ssl/termix.crt + chown node:node /app/data/ssl/termix.key /app/data/ssl/termix.crt # Clean up config - rm -f /app/ssl/openssl.conf + rm -f /app/data/ssl/openssl.conf echo "SSL certificates generated successfully for domain: $DOMAIN" fi diff --git a/src/backend/utils/auto-ssl-setup.ts b/src/backend/utils/auto-ssl-setup.ts index 74b8b0b5..adcf456b 100644 --- a/src/backend/utils/auto-ssl-setup.ts +++ b/src/backend/utils/auto-ssl-setup.ts @@ -14,10 +14,11 @@ import { systemLogger } from "./logger.js"; * - Users can enable SSL by setting ENABLE_SSL=true */ export class AutoSSLSetup { - private static readonly SSL_DIR = path.join(process.cwd(), "ssl"); + private static readonly DATA_DIR = process.env.DATA_DIR || "./db/data"; + private static readonly SSL_DIR = path.join(AutoSSLSetup.DATA_DIR, "ssl"); private static readonly CERT_FILE = path.join(AutoSSLSetup.SSL_DIR, "termix.crt"); private static readonly KEY_FILE = path.join(AutoSSLSetup.SSL_DIR, "termix.key"); - private static readonly ENV_FILE = path.join(process.cwd(), ".env"); + private static readonly ENV_FILE = path.join(AutoSSLSetup.DATA_DIR, ".env"); /** * Initialize SSL setup automatically during system startup @@ -218,10 +219,9 @@ IP.2 = ::1 operation: "ssl_env_setup" }); - // Use container paths in production, local paths in development - const isProduction = process.env.NODE_ENV === "production"; - const certPath = isProduction ? "/app/ssl/termix.crt" : this.CERT_FILE; - const keyPath = isProduction ? "/app/ssl/termix.key" : this.KEY_FILE; + // Use data directory paths for both production and development + const certPath = this.CERT_FILE; + const keyPath = this.KEY_FILE; const sslEnvVars = { ENABLE_SSL: "false", // Disable SSL by default to avoid setup issues diff --git a/src/ui/Desktop/Apps/File Manager/FileManager.tsx b/src/ui/Desktop/Apps/File Manager/FileManager.tsx index 7d7f9155..ef34759f 100644 --- a/src/ui/Desktop/Apps/File Manager/FileManager.tsx +++ b/src/ui/Desktop/Apps/File Manager/FileManager.tsx @@ -495,19 +495,14 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) { async function handleUploadFile(file: File) { if (!sshSessionId) return; - // Show progress for large files (>10MB) - const isLargeFile = file.size > 10 * 1024 * 1024; - let progressToast: any = null; - - if (isLargeFile) { - progressToast = toast.loading( - t("fileManager.uploadingLargeFile", { - name: file.name, - size: formatFileSize(file.size) - }), - { duration: Infinity } - ); - } + // Show progress for all file uploads + const progressToast = toast.loading( + t("fileManager.uploadingFile", { + name: file.name, + size: formatFileSize(file.size) + }), + { duration: Infinity } + ); try { // Ensure SSH connection is valid @@ -565,20 +560,16 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) { undefined, // userId - will be handled by backend ); - // Dismiss progress toast if it exists - if (progressToast) { - toast.dismiss(progressToast); - } + // Dismiss progress toast + toast.dismiss(progressToast); toast.success( t("fileManager.fileUploadedSuccessfully", { name: file.name }), ); handleRefreshDirectory(); } catch (error: any) { - // Dismiss progress toast if it exists - if (progressToast) { - toast.dismiss(progressToast); - } + // Dismiss progress toast + toast.dismiss(progressToast); if ( error.message?.includes("connection") || diff --git a/src/ui/Desktop/Apps/File Manager/components/DraggableWindow.tsx b/src/ui/Desktop/Apps/File Manager/components/DraggableWindow.tsx index 81ca0faf..89e40126 100644 --- a/src/ui/Desktop/Apps/File Manager/components/DraggableWindow.tsx +++ b/src/ui/Desktop/Apps/File Manager/components/DraggableWindow.tsx @@ -116,15 +116,53 @@ export function DraggableWindow({ const deltaX = e.clientX - dragStart.x; const deltaY = e.clientY - dragStart.y; + const newX = windowStart.x + deltaX; + const newY = windowStart.y + deltaY; + + // Find the positioning container by checking parent hierarchy + const windowElement = windowRef.current; + let positioningContainer = null; + let currentElement = windowElement?.parentElement; + + while (currentElement && currentElement !== document.body) { + const computedStyle = window.getComputedStyle(currentElement); + const position = computedStyle.position; + const transform = computedStyle.transform; + + if (position === 'relative' || position === 'absolute' || position === 'fixed' || transform !== 'none') { + positioningContainer = currentElement; + break; + } + + currentElement = currentElement.parentElement; + } + + // Calculate boundaries based on the actual positioning context + let maxX, maxY, minX, minY; + + if (positioningContainer) { + const containerRect = positioningContainer.getBoundingClientRect(); + + // Window is positioned relative to a positioning container + maxX = containerRect.width - size.width; + maxY = containerRect.height - size.height; + minX = 0; + minY = 0; + } else { + // Window is positioned relative to viewport + maxX = window.innerWidth - size.width; + maxY = window.innerHeight - size.height; + minX = 0; + minY = 0; + } + + // Ensure window stays within boundaries + const constrainedX = Math.max(minX, Math.min(maxX, newX)); + const constrainedY = Math.max(minY, Math.min(maxY, newY)); + setPosition({ - x: Math.max( - 0, - Math.min(window.innerWidth - size.width, windowStart.x + deltaX), - ), - y: Math.max( - 0, - Math.min(window.innerHeight - 40, windowStart.y + deltaY), - ), // Keep title bar visible + x: constrainedX, + y: constrainedY, }); }