mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-03 08:53:36 +00:00
feat: enhance terminal input validation and update keyboard shortcuts
- Added validation for terminal input to ensure it is a string and limited to 1MB to prevent memory issues. - Implemented checks for terminal resize dimensions to ensure they are positive integers within specified bounds. - Updated keyboard shortcuts for terminal actions to use Alt key combinations instead of Ctrl+Shift for better accessibility.
This commit is contained in:
@@ -297,11 +297,34 @@ terminalWss.on(
|
|||||||
|
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case "input":
|
case "input":
|
||||||
|
// Validate input data type and length
|
||||||
|
if (typeof msg.data !== "string") {
|
||||||
|
ws.send(JSON.stringify({ type: "error", message: "Invalid input type" }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Limit input size to 1MB to prevent memory issues
|
||||||
|
if (msg.data.length > 1024 * 1024) {
|
||||||
|
ws.send(JSON.stringify({ type: "error", message: "Input too large" }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Write user input to terminal
|
// Write user input to terminal
|
||||||
terminalService.write(sessionId, msg.data);
|
terminalService.write(sessionId, msg.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "resize":
|
case "resize":
|
||||||
|
// Validate resize dimensions are positive integers within reasonable bounds
|
||||||
|
if (
|
||||||
|
typeof msg.cols !== "number" ||
|
||||||
|
typeof msg.rows !== "number" ||
|
||||||
|
!Number.isInteger(msg.cols) ||
|
||||||
|
!Number.isInteger(msg.rows) ||
|
||||||
|
msg.cols < 1 ||
|
||||||
|
msg.cols > 1000 ||
|
||||||
|
msg.rows < 1 ||
|
||||||
|
msg.rows > 500
|
||||||
|
) {
|
||||||
|
break; // Silently ignore invalid resize requests
|
||||||
|
}
|
||||||
// Resize terminal with deduplication and rate limiting
|
// Resize terminal with deduplication and rate limiting
|
||||||
if (msg.cols && msg.rows) {
|
if (msg.cols && msg.rows) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Common utilities and state for terminal routes
|
* Common utilities and state for terminal routes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { randomBytes } from "crypto";
|
||||||
import { createLogger } from "../../lib/logger.js";
|
import { createLogger } from "../../lib/logger.js";
|
||||||
import type { Request, Response, NextFunction } from "express";
|
import type { Request, Response, NextFunction } from "express";
|
||||||
import { getTerminalService } from "../../services/terminal-service.js";
|
import { getTerminalService } from "../../services/terminal-service.js";
|
||||||
@@ -49,12 +50,10 @@ export function getTokenData(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a secure random token
|
* Generate a cryptographically secure random token
|
||||||
*/
|
*/
|
||||||
export function generateToken(): string {
|
export function generateToken(): string {
|
||||||
return `term-${Date.now()}-${Math.random()
|
return `term-${randomBytes(32).toString("base64url")}`;
|
||||||
.toString(36)
|
|
||||||
.slice(2, 17)}${Math.random().toString(36).slice(2, 17)}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -668,8 +668,8 @@ export function TerminalPanel({
|
|||||||
// Use event.code for keyboard-layout-independent key detection
|
// Use event.code for keyboard-layout-independent key detection
|
||||||
const code = event.code;
|
const code = event.code;
|
||||||
|
|
||||||
// Ctrl+Shift+D - Split right (uses Ctrl+Shift to avoid Alt+D readline conflict)
|
// Alt+D - Split right
|
||||||
if (event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey && code === 'KeyD') {
|
if (event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey && code === 'KeyD') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (canTrigger) {
|
if (canTrigger) {
|
||||||
lastShortcutTimeRef.current = now;
|
lastShortcutTimeRef.current = now;
|
||||||
@@ -678,8 +678,8 @@ export function TerminalPanel({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ctrl+Shift+S - Split down (uses Ctrl+Shift to avoid readline conflicts)
|
// Alt+S - Split down
|
||||||
if (event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey && code === 'KeyS') {
|
if (event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey && code === 'KeyS') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (canTrigger) {
|
if (canTrigger) {
|
||||||
lastShortcutTimeRef.current = now;
|
lastShortcutTimeRef.current = now;
|
||||||
@@ -688,8 +688,8 @@ export function TerminalPanel({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ctrl+Shift+W - Close terminal (uses Ctrl+Shift to avoid readline conflicts)
|
// Alt+W - Close terminal
|
||||||
if (event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey && code === 'KeyW') {
|
if (event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey && code === 'KeyW') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (canTrigger) {
|
if (canTrigger) {
|
||||||
lastShortcutTimeRef.current = now;
|
lastShortcutTimeRef.current = now;
|
||||||
@@ -698,8 +698,8 @@ export function TerminalPanel({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ctrl+Shift+T - New terminal tab (uses Ctrl+Shift for consistency)
|
// Alt+T - New terminal tab
|
||||||
if (event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey && code === 'KeyT') {
|
if (event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey && code === 'KeyT') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (canTrigger && onNewTabRef.current) {
|
if (canTrigger && onNewTabRef.current) {
|
||||||
lastShortcutTimeRef.current = now;
|
lastShortcutTimeRef.current = now;
|
||||||
@@ -1757,7 +1757,7 @@ export function TerminalPanel({
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onSplitHorizontal();
|
onSplitHorizontal();
|
||||||
}}
|
}}
|
||||||
title="Split Right (Cmd+D)"
|
title="Split Right (Alt+D)"
|
||||||
>
|
>
|
||||||
<SplitSquareHorizontal className="h-3 w-3" />
|
<SplitSquareHorizontal className="h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1769,7 +1769,7 @@ export function TerminalPanel({
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onSplitVertical();
|
onSplitVertical();
|
||||||
}}
|
}}
|
||||||
title="Split Down (Cmd+Shift+D)"
|
title="Split Down (Alt+S)"
|
||||||
>
|
>
|
||||||
<SplitSquareVertical className="h-3 w-3" />
|
<SplitSquareVertical className="h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1799,7 +1799,7 @@ export function TerminalPanel({
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onClose();
|
onClose();
|
||||||
}}
|
}}
|
||||||
title="Close Terminal (Cmd+W)"
|
title="Close Terminal (Alt+W)"
|
||||||
>
|
>
|
||||||
<X className="h-3 w-3" />
|
<X className="h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user