Fix certificate regeneration, svg files encrypting, and file manager being able to be dragged off screen.
This commit is contained in:
@@ -21,6 +21,8 @@ services:
|
|||||||
PORT: "4300"
|
PORT: "4300"
|
||||||
ENABLE_SSL: "true"
|
ENABLE_SSL: "true"
|
||||||
SSL_DOMAIN: "termix-dev.karmaa.site"
|
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
|
# Resource limits for better large file handling
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ set -e
|
|||||||
export PORT=${PORT:-8080}
|
export PORT=${PORT:-8080}
|
||||||
export ENABLE_SSL=${ENABLE_SSL:-false}
|
export ENABLE_SSL=${ENABLE_SSL:-false}
|
||||||
export SSL_PORT=${SSL_PORT:-8443}
|
export SSL_PORT=${SSL_PORT:-8443}
|
||||||
export SSL_CERT_PATH=${SSL_CERT_PATH:-/app/ssl/termix.crt}
|
export SSL_CERT_PATH=${SSL_CERT_PATH:-/app/data/ssl/termix.crt}
|
||||||
export SSL_KEY_PATH=${SSL_KEY_PATH:-/app/ssl/termix.key}
|
export SSL_KEY_PATH=${SSL_KEY_PATH:-/app/data/ssl/termix.key}
|
||||||
|
|
||||||
echo "Configuring web UI to run on port: $PORT"
|
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 SSL is enabled, generate certificates first
|
||||||
if [ "$ENABLE_SSL" = "true" ]; then
|
if [ "$ENABLE_SSL" = "true" ]; then
|
||||||
echo "Generating SSL certificates..."
|
echo "Generating SSL certificates..."
|
||||||
mkdir -p /app/ssl
|
mkdir -p /app/data/ssl
|
||||||
chown -R node:node /app/ssl
|
chown -R node:node /app/data/ssl
|
||||||
chmod 755 /app/ssl
|
chmod 755 /app/data/ssl
|
||||||
|
|
||||||
# Generate SSL certificates using OpenSSL directly (faster and more reliable)
|
# Generate SSL certificates using OpenSSL directly (faster and more reliable)
|
||||||
DOMAIN=${SSL_DOMAIN:-localhost}
|
DOMAIN=${SSL_DOMAIN:-localhost}
|
||||||
echo "Generating certificate for domain: $DOMAIN"
|
echo "Generating certificate for domain: $DOMAIN"
|
||||||
|
|
||||||
# Create OpenSSL config
|
# Create OpenSSL config
|
||||||
cat > /app/ssl/openssl.conf << EOF
|
cat > /app/data/ssl/openssl.conf << EOF
|
||||||
[req]
|
[req]
|
||||||
default_bits = 2048
|
default_bits = 2048
|
||||||
prompt = no
|
prompt = no
|
||||||
@@ -69,18 +69,18 @@ IP.2 = ::1
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Generate private key
|
# Generate private key
|
||||||
openssl genrsa -out /app/ssl/termix.key 2048
|
openssl genrsa -out /app/data/ssl/termix.key 2048
|
||||||
|
|
||||||
# Generate certificate
|
# 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
|
# Set proper permissions
|
||||||
chmod 600 /app/ssl/termix.key
|
chmod 600 /app/data/ssl/termix.key
|
||||||
chmod 644 /app/ssl/termix.crt
|
chmod 644 /app/data/ssl/termix.crt
|
||||||
chown node:node /app/ssl/termix.key /app/ssl/termix.crt
|
chown node:node /app/data/ssl/termix.key /app/data/ssl/termix.crt
|
||||||
|
|
||||||
# Clean up config
|
# Clean up config
|
||||||
rm -f /app/ssl/openssl.conf
|
rm -f /app/data/ssl/openssl.conf
|
||||||
|
|
||||||
echo "SSL certificates generated successfully for domain: $DOMAIN"
|
echo "SSL certificates generated successfully for domain: $DOMAIN"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ import { systemLogger } from "./logger.js";
|
|||||||
* - Users can enable SSL by setting ENABLE_SSL=true
|
* - Users can enable SSL by setting ENABLE_SSL=true
|
||||||
*/
|
*/
|
||||||
export class AutoSSLSetup {
|
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 CERT_FILE = path.join(AutoSSLSetup.SSL_DIR, "termix.crt");
|
||||||
private static readonly KEY_FILE = path.join(AutoSSLSetup.SSL_DIR, "termix.key");
|
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
|
* Initialize SSL setup automatically during system startup
|
||||||
@@ -218,10 +219,9 @@ IP.2 = ::1
|
|||||||
operation: "ssl_env_setup"
|
operation: "ssl_env_setup"
|
||||||
});
|
});
|
||||||
|
|
||||||
// Use container paths in production, local paths in development
|
// Use data directory paths for both production and development
|
||||||
const isProduction = process.env.NODE_ENV === "production";
|
const certPath = this.CERT_FILE;
|
||||||
const certPath = isProduction ? "/app/ssl/termix.crt" : this.CERT_FILE;
|
const keyPath = this.KEY_FILE;
|
||||||
const keyPath = isProduction ? "/app/ssl/termix.key" : this.KEY_FILE;
|
|
||||||
|
|
||||||
const sslEnvVars = {
|
const sslEnvVars = {
|
||||||
ENABLE_SSL: "false", // Disable SSL by default to avoid setup issues
|
ENABLE_SSL: "false", // Disable SSL by default to avoid setup issues
|
||||||
|
|||||||
@@ -495,19 +495,14 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) {
|
|||||||
async function handleUploadFile(file: File) {
|
async function handleUploadFile(file: File) {
|
||||||
if (!sshSessionId) return;
|
if (!sshSessionId) return;
|
||||||
|
|
||||||
// Show progress for large files (>10MB)
|
// Show progress for all file uploads
|
||||||
const isLargeFile = file.size > 10 * 1024 * 1024;
|
const progressToast = toast.loading(
|
||||||
let progressToast: any = null;
|
t("fileManager.uploadingFile", {
|
||||||
|
|
||||||
if (isLargeFile) {
|
|
||||||
progressToast = toast.loading(
|
|
||||||
t("fileManager.uploadingLargeFile", {
|
|
||||||
name: file.name,
|
name: file.name,
|
||||||
size: formatFileSize(file.size)
|
size: formatFileSize(file.size)
|
||||||
}),
|
}),
|
||||||
{ duration: Infinity }
|
{ duration: Infinity }
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Ensure SSH connection is valid
|
// Ensure SSH connection is valid
|
||||||
@@ -565,20 +560,16 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) {
|
|||||||
undefined, // userId - will be handled by backend
|
undefined, // userId - will be handled by backend
|
||||||
);
|
);
|
||||||
|
|
||||||
// Dismiss progress toast if it exists
|
// Dismiss progress toast
|
||||||
if (progressToast) {
|
|
||||||
toast.dismiss(progressToast);
|
toast.dismiss(progressToast);
|
||||||
}
|
|
||||||
|
|
||||||
toast.success(
|
toast.success(
|
||||||
t("fileManager.fileUploadedSuccessfully", { name: file.name }),
|
t("fileManager.fileUploadedSuccessfully", { name: file.name }),
|
||||||
);
|
);
|
||||||
handleRefreshDirectory();
|
handleRefreshDirectory();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
// Dismiss progress toast if it exists
|
// Dismiss progress toast
|
||||||
if (progressToast) {
|
|
||||||
toast.dismiss(progressToast);
|
toast.dismiss(progressToast);
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
error.message?.includes("connection") ||
|
error.message?.includes("connection") ||
|
||||||
|
|||||||
@@ -116,15 +116,53 @@ export function DraggableWindow({
|
|||||||
const deltaX = e.clientX - dragStart.x;
|
const deltaX = e.clientX - dragStart.x;
|
||||||
const deltaY = e.clientY - dragStart.y;
|
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({
|
setPosition({
|
||||||
x: Math.max(
|
x: constrainedX,
|
||||||
0,
|
y: constrainedY,
|
||||||
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
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user