feat: initial commit of Ghaymah internal DNS, TCP and security testing suite and report
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
const WSS_URL = 'wss://client-terminal-0f1fe89209a8.hosted.ghaymah.systems/ws';
|
||||
|
||||
class RemoteTerminal {
|
||||
constructor() {
|
||||
this.ws = null;
|
||||
this.ready = false;
|
||||
}
|
||||
|
||||
async connect() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ws = new WebSocket(WSS_URL, ['tty']);
|
||||
|
||||
this.ws.onopen = () => {
|
||||
this.ws.send(JSON.stringify({ AuthToken: '' }));
|
||||
this.ws.send('1' + JSON.stringify({ columns: 200, rows: 50 }));
|
||||
setTimeout(() => {
|
||||
this.ready = true;
|
||||
resolve();
|
||||
}, 800);
|
||||
};
|
||||
|
||||
this.ws.onerror = (e) => reject(new Error('WS error: ' + e.message));
|
||||
});
|
||||
}
|
||||
|
||||
async exec(command, timeoutMs = 10000) {
|
||||
if (!this.ready) await this.connect();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const markerId = Math.random().toString(36).substring(2, 8);
|
||||
let rawOutput = '';
|
||||
let timer = null;
|
||||
|
||||
const messageHandler = async (event) => {
|
||||
let text = '';
|
||||
if (event.data instanceof Blob) {
|
||||
text = await event.data.text();
|
||||
} else if (typeof event.data === 'string') {
|
||||
text = event.data;
|
||||
} else {
|
||||
text = Buffer.from(event.data).toString('utf8');
|
||||
}
|
||||
if (text.startsWith('0')) text = text.substring(1);
|
||||
rawOutput += text;
|
||||
|
||||
// Match \n__RET__<code|marker>__END__ when printed by echo, NOT during command typing
|
||||
const regex = new RegExp(`\r?\n__RET__(\\d+)_${markerId}__END__`);
|
||||
const match = rawOutput.match(regex);
|
||||
|
||||
if (match) {
|
||||
cleanup();
|
||||
const clean = rawOutput
|
||||
.replace(/[\x1b\x9b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '')
|
||||
.replace(/\r/g, '');
|
||||
|
||||
const exitCode = parseInt(match[1]);
|
||||
const lines = clean.split('\n');
|
||||
|
||||
// Find the line where the command was echoed
|
||||
const cmdIdx = lines.findIndex(l => l.includes(markerId) && l.includes('echo'));
|
||||
// Find the line where the result marker is
|
||||
const retIdx = lines.findIndex(l => l.startsWith(`__RET__${exitCode}_${markerId}__END__`));
|
||||
|
||||
let outLines = [];
|
||||
if (cmdIdx !== -1 && retIdx !== -1 && retIdx > cmdIdx) {
|
||||
outLines = lines.slice(cmdIdx + 1, retIdx);
|
||||
} else if (retIdx !== -1) {
|
||||
outLines = lines.slice(0, retIdx);
|
||||
} else {
|
||||
outLines = lines;
|
||||
}
|
||||
|
||||
// Filter out prompt lines
|
||||
const filtered = outLines.filter(l => !l.endsWith('~#') && !l.endsWith('$') && !l.includes('bash ('));
|
||||
|
||||
resolve({
|
||||
command,
|
||||
output: filtered.join('\n').trim(),
|
||||
exitCode,
|
||||
raw: rawOutput
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const cleanup = () => {
|
||||
clearTimeout(timer);
|
||||
this.ws.removeEventListener('message', messageHandler);
|
||||
};
|
||||
|
||||
timer = setTimeout(() => {
|
||||
cleanup();
|
||||
resolve({
|
||||
command,
|
||||
output: rawOutput.replace(/[\x1b\x9b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '').trim(),
|
||||
exitCode: -1,
|
||||
timedOut: true
|
||||
});
|
||||
}, timeoutMs);
|
||||
|
||||
this.ws.addEventListener('message', messageHandler);
|
||||
|
||||
// Execute command and output return marker
|
||||
const fullCmd = `${command}; echo __RET__$?_${markerId}__END__\n`;
|
||||
this.ws.send('0' + fullCmd);
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.ws) {
|
||||
try { this.ws.close(); } catch (e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { RemoteTerminal };
|
||||
|
||||
if (require.main === module) {
|
||||
(async () => {
|
||||
const term = new RemoteTerminal();
|
||||
await term.connect();
|
||||
console.log('Connected! Testing uname -a...');
|
||||
const res1 = await term.exec('uname -a');
|
||||
console.log('--- OUTPUT 1 ---');
|
||||
console.log(res1.output);
|
||||
console.log('Exit code:', res1.exitCode);
|
||||
|
||||
console.log('\nTesting cat /etc/resolv.conf...');
|
||||
const res2 = await term.exec('cat /etc/resolv.conf');
|
||||
console.log('--- OUTPUT 2 ---');
|
||||
console.log(res2.output);
|
||||
console.log('Exit code:', res2.exitCode);
|
||||
|
||||
term.close();
|
||||
})().catch(console.error);
|
||||
}
|
||||
Reference in New Issue
Block a user