Skip to content

Commit 481e747

Browse files
authored
Feat/some improvements to terminal and its api (#1463)
* feat: add little padding to terminal area * feat: add a check in terminal plugin api to avoid dangerous commands
1 parent 844a731 commit 481e747

File tree

3 files changed

+111
-2
lines changed

3 files changed

+111
-2
lines changed

src/components/terminal/terminal.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ export default class TerminalComponent {
468468
position: relative;
469469
background: ${this.options.theme.background};
470470
overflow: hidden;
471+
padding: 0.25rem;
472+
box-sizing: border-box;
471473
`;
472474

473475
return this.container;
@@ -691,7 +693,18 @@ export default class TerminalComponent {
691693
* @param {string} data - Data to write
692694
*/
693695
write(data) {
694-
this.terminal.write(data);
696+
if (
697+
this.serverMode &&
698+
this.isConnected &&
699+
this.websocket &&
700+
this.websocket.readyState === WebSocket.OPEN
701+
) {
702+
// Send data through WebSocket instead of direct write
703+
this.websocket.send(data);
704+
} else {
705+
// For local mode or disconnected terminals, write directly
706+
this.terminal.write(data);
707+
}
695708
}
696709

697710
/**

src/components/terminal/terminalManager.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ class TerminalManager {
472472
background: #1e1e1e;
473473
overflow: hidden;
474474
position: relative;
475+
padding: 0.25rem;
475476
}
476477
`;
477478
}

src/lib/acode.js

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export default class Acode {
103103
createServer: (options) => TerminalManager.createServerTerminal(options),
104104
get: (id) => TerminalManager.getTerminal(id),
105105
getAll: () => TerminalManager.getAllTerminals(),
106-
write: (id, data) => TerminalManager.writeToTerminal(id, data),
106+
write: (id, data) => this.#secureTerminalWrite(id, data),
107107
clear: (id) => TerminalManager.clearTerminal(id),
108108
close: (id) => TerminalManager.closeTerminal(id),
109109
themes: {
@@ -162,6 +162,101 @@ export default class Acode {
162162
this.define("toInternalUrl", helpers.toInternalUri);
163163
}
164164

165+
/**
166+
* Secure terminal write with command validation
167+
* Prevents execution of malicious or dangerous commands through plugin API
168+
* @param {string} id - Terminal ID
169+
* @param {string} data - Data to write
170+
*/
171+
#secureTerminalWrite(id, data) {
172+
if (typeof data !== "string") {
173+
console.warn("Terminal write data must be a string");
174+
return;
175+
}
176+
177+
// List of potentially dangerous commands/patterns to block
178+
const dangerousPatterns = [
179+
// System commands that can cause damage
180+
/^\s*rm\s+-rf?\s+\/[^\r\n]*[\r\n]?$/m,
181+
/^\s*rm\s+-rf?\s+\*[^\r\n]*[\r\n]?$/m,
182+
/^\s*rm\s+-rf?\s+~[^\r\n]*[\r\n]?$/m,
183+
/^\s*mkfs\.[^\r\n]*[\r\n]?$/m,
184+
/^\s*dd\s+if=\/[^\r\n]*[\r\n]?$/m,
185+
/^\s*:(){ :|:& };:[^\r\n]*[\r\n]?$/m, // Fork bomb
186+
/^\s*sudo\s+dd\s+if=\/[^\r\n]*[\r\n]?$/m,
187+
/^\s*sudo\s+rm\s+-rf?\s+\/[^\r\n]*[\r\n]?$/m,
188+
/^\s*curl\s+[^\r\n]*\|\s*sh[^\r\n]*[\r\n]?$/m,
189+
/^\s*wget\s+[^\r\n]*\|\s*sh[^\r\n]*[\r\n]?$/m,
190+
/^\s*bash\s+<\s*\([^\r\n]*[\r\n]?$/m,
191+
/^\s*sh\s+<\s*\([^\r\n]*[\r\n]?$/m,
192+
193+
// Network-based attacks
194+
/^\s*nc\s+-l\s+-p\s+\d+[^\r\n]*[\r\n]?$/m,
195+
/^\s*ncat\s+-l\s+-p\s+\d+[^\r\n]*[\r\n]?$/m,
196+
/^\s*python\s+.*SimpleHTTPServer[^\r\n]*[\r\n]?$/m,
197+
/^\s*python\s+.*http\.server[^\r\n]*[\r\n]?$/m,
198+
199+
// Process manipulation
200+
/^\s*kill\s+-9\s+1\s*[\r\n]?$/m,
201+
/^\s*killall\s+-9\s+\*[^\r\n]*[\r\n]?$/m,
202+
203+
// File system manipulation
204+
/^\s*chmod\s+777\s+\/[^\r\n]*[\r\n]?$/m,
205+
/^\s*chown\s+[^\s]+\s+\/[^\r\n]*[\r\n]?$/m,
206+
207+
// Sensitive file access attempts
208+
/^\s*cat\s+\/etc\/passwd[^\r\n]*[\r\n]?$/m,
209+
/^\s*cat\s+\/etc\/shadow[^\r\n]*[\r\n]?$/m,
210+
/^\s*cat\s+\/root\/[^\r\n]*[\r\n]?$/m,
211+
212+
// Only block null bytes
213+
/\x00/g,
214+
];
215+
216+
// Check for dangerous patterns
217+
for (const pattern of dangerousPatterns) {
218+
if (pattern.test(data)) {
219+
console.warn(
220+
`Blocked potentially dangerous terminal command: ${data.substring(0, 50)}...`,
221+
);
222+
toast("Potentially dangerous command blocked for security", 3000);
223+
return;
224+
}
225+
}
226+
227+
// Additional checks for suspicious character sequences
228+
if (data.includes("$(") && data.includes(")")) {
229+
const commandSubstitution = /\$\([^)]*\)/g;
230+
const matches = data.match(commandSubstitution);
231+
if (matches) {
232+
for (const match of matches) {
233+
// Check if command substitution contains dangerous commands
234+
for (const pattern of dangerousPatterns) {
235+
if (pattern.test(match)) {
236+
console.warn(
237+
`Blocked command substitution with dangerous content: ${match}`,
238+
);
239+
toast("Command substitution blocked for security", 3000);
240+
return;
241+
}
242+
}
243+
}
244+
}
245+
}
246+
247+
// Sanitize data length to prevent memory exhaustion
248+
const maxLength = 64 * 1024; // 64KB max per write
249+
if (data.length > maxLength) {
250+
console.warn(
251+
`Terminal write data truncated - exceeded ${maxLength} characters`,
252+
);
253+
data = data.substring(0, maxLength) + "\n[Data truncated for security]\n";
254+
}
255+
256+
// If all security checks pass, proceed with writing
257+
return TerminalManager.writeToTerminal(id, data);
258+
}
259+
165260
/**
166261
* Define a module
167262
* @param {string} name

0 commit comments

Comments
 (0)