Skip to content

Commit 230d0d3

Browse files
authored
[Feature] Add synchronous socket shell execution to daemon and agent (#45)
* Added synchronous socket connection on the agent's side * Moved all configuration parameters into * Now removing temp script dir after command exec * Updated shell_exec_sync comm method on agent * Added basic socket.io comms for saas connections * Added launch.json to agent because of vscode issues * Added authentication to socket.io and now sending pid on event
1 parent 6e5523c commit 230d0d3

File tree

16 files changed

+640
-64
lines changed

16 files changed

+640
-64
lines changed

agent/.vscode/launch.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"configurations": [
3+
{
4+
"type": "node-terminal",
5+
"name": "Run Script: dev",
6+
"request": "launch",
7+
"command": "npm run dev",
8+
"cwd": "${workspaceFolder}"
9+
}
10+
]
11+
}

agent/package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

agent/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"dependencies": {
2525
"dotenv": "^10.0.0",
2626
"log4js": "^6.4.1",
27+
"mktemp": "^1.0.0",
2728
"node-fetch": "^2.6.7",
2829
"node-pty": "^0.10.1",
2930
"passwd-linux": "^2.0.0",

agent/src/lib/typing/MessageData.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,12 @@ interface possibleArgs {
3838
password?: string;
3939
errorReport?: CommandErrorReport | ErrorReport;
4040
lines?: string | null;
41-
status?: 'success' | 'error';
41+
status?: 'success' | 'error' | 'running';
4242
ticket?: TicketOptions;
43+
script?: string;
44+
output?: string;
45+
outputType?: 'stdout' | 'stderr';
46+
exitCode?: number;
4347
}
4448

4549
export class InvalidMessageError extends Error {

agent/src/lib/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,5 @@ export function checkIfSocketClosed(socket: WebSocket): boolean {
122122
);
123123
}
124124

125-
export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
125+
export const delay = (ms: number) =>
126+
new Promise((resolve) => setTimeout(resolve, ms));

agent/src/ws/MessageRouting.ts

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import { ExecException } from 'child_process';
1+
import { exec, ExecException } from 'child_process';
22
import Agent from '../Agent';
33
import { CommandErrorReport, ErrorReport } from '../lib/typing/types';
44
import { MessageDataResponse } from '../lib/typing/MessageData';
55
import { Task } from '../lib/typing/Task';
66
import { execAsync, getLastLines } from '../lib/utils';
77
import { ActualExecException, ExecReportError } from '../lib/typing/errors';
88
import Ticket from '../lib/typing/Ticket';
9+
import { chmodSync, mkdtempSync, writeFileSync } from 'fs';
10+
import { rm } from 'fs/promises';
911

1012
export default class MessageRouting {
1113
[key: string]: (agent: Agent, task: Task) => Promise<void>;
@@ -139,4 +141,103 @@ export default class MessageRouting {
139141

140142
agent.sendData(clientCommand);
141143
}
144+
145+
public static async shell_exec_sync(
146+
agent: Agent,
147+
task: Task
148+
): Promise<void> {
149+
const script: string = task.data.args.script;
150+
try {
151+
const tmpDir = mkdtempSync('cw-', { encoding: 'utf-8' });
152+
const tmpScriptPath = `${tmpDir}/script.sh`;
153+
writeFileSync(tmpScriptPath, script, {
154+
encoding: 'utf-8',
155+
flag: 'w',
156+
});
157+
chmodSync(tmpScriptPath, 0o755);
158+
159+
const shell = exec(`/bin/bash ${tmpScriptPath}`);
160+
161+
shell.stdout.on('data', (data) => {
162+
const clientCommand: MessageDataResponse =
163+
new MessageDataResponse({
164+
taskid: task.id,
165+
action: 'shell_exec_sync',
166+
args: {
167+
output: String(data),
168+
outputType: 'stdout',
169+
},
170+
});
171+
172+
agent.sendData(clientCommand);
173+
});
174+
175+
shell.stderr.on('data', (data) => {
176+
const clientCommand: MessageDataResponse =
177+
new MessageDataResponse({
178+
taskid: task.id,
179+
action: 'shell_exec_sync',
180+
args: {
181+
output: String(data),
182+
outputType: 'stderr',
183+
},
184+
});
185+
186+
agent.sendData(clientCommand);
187+
188+
shell.kill('SIGKILL');
189+
});
190+
191+
shell.on('exit', (code: number) => {
192+
const clientCommand: MessageDataResponse =
193+
new MessageDataResponse({
194+
taskid: task.id,
195+
action: 'shell_exec_sync',
196+
args: {
197+
status: code === 0 ? 'success' : 'error',
198+
exitCode: code,
199+
},
200+
});
201+
202+
agent.sendData(clientCommand);
203+
agent.logger.info(
204+
`Finished executing script with id: ${task.id}`
205+
);
206+
});
207+
208+
// TODO: Handle timeout
209+
210+
agent.logger.info(`Executed script with task id: ${task.id}`);
211+
rm(tmpDir, { recursive: true, force: true }).catch(() => {
212+
agent.logger.error('Could not delete temporary exec directory');
213+
});
214+
const clientCommand: MessageDataResponse = new MessageDataResponse({
215+
taskid: task.id,
216+
action: 'shell_exec_sync',
217+
args: {
218+
status: 'running',
219+
},
220+
});
221+
222+
agent.sendData(clientCommand);
223+
} catch (e) {
224+
agent.logger.error(
225+
`Failed executing script with task id: ${task.id}, with error: ${e}`
226+
);
227+
228+
const clientCommand: MessageDataResponse = new MessageDataResponse({
229+
taskid: task.id,
230+
action: 'shell_exec_sync',
231+
args: {
232+
status: 'error',
233+
errorReport: {
234+
message: e.message,
235+
stack: e.stack,
236+
},
237+
},
238+
});
239+
240+
agent.sendData(clientCommand);
241+
}
242+
}
142243
}

0 commit comments

Comments
 (0)