|
|
@ -3,6 +3,17 @@ const { spawn } = require('child_process'); |
|
|
|
const { EOL } = require('os'); |
|
|
|
const os = require('os'); |
|
|
|
|
|
|
|
// Runtime
|
|
|
|
const runtime = { |
|
|
|
home: os.homedir(), |
|
|
|
hostname: os.hostname(), |
|
|
|
username: os.userInfo().username, |
|
|
|
shell: os.platform() === 'win32' ? 'cmd.exe' : 'bash', |
|
|
|
sessions: [], |
|
|
|
identifierState: 0, |
|
|
|
history: [], |
|
|
|
} |
|
|
|
|
|
|
|
// Modules
|
|
|
|
const Telegraf = require('telegraf'); |
|
|
|
|
|
|
@ -28,37 +39,27 @@ const dateOptions = { |
|
|
|
}; |
|
|
|
|
|
|
|
const bot = new Telegraf(config.botApiKey); |
|
|
|
const sessions = []; |
|
|
|
let identifierState = 0; |
|
|
|
sessions.history = []; |
|
|
|
|
|
|
|
const getSession = sessionFinder(sessions); |
|
|
|
|
|
|
|
// get os info
|
|
|
|
const home = os.homedir(); |
|
|
|
const hostname = os.hostname(); |
|
|
|
const username = os.userInfo().username; |
|
|
|
const defaultShell = os.platform() === 'win32' ? 'cmd.exe' : 'bash'; |
|
|
|
const getSession = sessionFinder(runtime.sessions); |
|
|
|
|
|
|
|
// Validate bot's master
|
|
|
|
bot.use(validator); |
|
|
|
|
|
|
|
bot.command('start', |
|
|
|
ctx => { |
|
|
|
const newProc = spawn(defaultShell, { |
|
|
|
cwd: home |
|
|
|
const newProc = spawn(runtime.shell, { |
|
|
|
cwd: runtime.home |
|
|
|
}); |
|
|
|
const identifier = extractCommandText('start')(ctx); |
|
|
|
if(identifier) newProc.identifier = identifier; |
|
|
|
else newProc.identifier = identifierState; |
|
|
|
newProc.index = identifierState; |
|
|
|
sessions[identifierState] = newProc; |
|
|
|
identifierState++; |
|
|
|
sessions.currentSession = newProc; |
|
|
|
listeners.add(sessions.currentSession, responder, ctx); |
|
|
|
else newProc.identifier = runtime.identifierState; |
|
|
|
newProc.index = runtime.identifierState; |
|
|
|
runtime.sessions[runtime.identifierState] = newProc; |
|
|
|
runtime.identifierState++; |
|
|
|
runtime.sessions.currentSession = newProc; |
|
|
|
listeners.add(runtime.sessions.currentSession, responder, ctx); |
|
|
|
return responder.success(`Welcome to tsh -- <code>Telegram Shell!</code>\n\n` |
|
|
|
+ `You are now connected to <code>${hostname}</code>` |
|
|
|
+ ` as <strong>${username}</strong>.`, |
|
|
|
+ `You are now connected to <code>${runtime.hostname}</code>` |
|
|
|
+ ` as <strong>${runtime.username}</strong>.`, |
|
|
|
'html' |
|
|
|
)(ctx); |
|
|
|
}); |
|
|
@ -67,13 +68,13 @@ bot.command('save', |
|
|
|
ctx => { |
|
|
|
const identifier = extractCommandText('save')(ctx); |
|
|
|
if(!identifier) return responder.fail('Need a valid identifier to save session.')(ctx); |
|
|
|
sessions.currentSession.identifier = identifier; |
|
|
|
runtime.sessions.currentSession.identifier = identifier; |
|
|
|
return responder.success(`Saved session <code>${identifier}</code>.`, 'html')(ctx); |
|
|
|
}); |
|
|
|
|
|
|
|
bot.command('ls', |
|
|
|
ctx => ctx.reply( |
|
|
|
sessions.reduce((acc, session) => |
|
|
|
runtime.sessions.reduce((acc, session) => |
|
|
|
acc ? `${acc}\n${session.identifier}` : `${session.identifier}`, '') |
|
|
|
|| `No sessions found. Start one with /start.` |
|
|
|
)); |
|
|
@ -83,41 +84,41 @@ bot.command('attach', |
|
|
|
const session = getSession(ctx)('attach'); |
|
|
|
if(!session) |
|
|
|
return responder.fail('Session not found. /ls for list of sessions')(ctx); |
|
|
|
sessions.currentSession = session; |
|
|
|
listeners.add(sessions.currentSession, responder, ctx); |
|
|
|
runtime.sessions.currentSession = session; |
|
|
|
listeners.add(runtime.sessions.currentSession, responder, ctx); |
|
|
|
return responder.success(`Reattached to shell ${session.identifier}`)(ctx); |
|
|
|
}); |
|
|
|
|
|
|
|
bot.command('detach', |
|
|
|
ctx => { |
|
|
|
const session = getSession(ctx)('detach') || sessions.currentSession; |
|
|
|
const session = getSession(ctx)('detach') || runtime.sessions.currentSession; |
|
|
|
if(!session) |
|
|
|
return responder.fail('Session not found. /ls for list of sessions.')(ctx); |
|
|
|
listeners.remove(session); |
|
|
|
sessions.currentSession = undefined; |
|
|
|
runtime.sessions.currentSession = undefined; |
|
|
|
return responder.success(`Detached from shell ${session.identifier}`)(ctx); |
|
|
|
}); |
|
|
|
|
|
|
|
bot.command('kill', |
|
|
|
ctx => { |
|
|
|
const session = getSession(ctx)('kill') || sessions.currentSession; |
|
|
|
const session = getSession(ctx)('kill') || runtime.sessions.currentSession; |
|
|
|
if(!session) |
|
|
|
return responder.fail('Session not found. /ls for list of sessions.')(ctx); |
|
|
|
session.kill(); |
|
|
|
delete sessions[session.index]; |
|
|
|
if(session === sessions.currentSession) sessions.currentSession = undefined; |
|
|
|
delete runtime.sessions[session.index]; |
|
|
|
if(session === runtime.sessions.currentSession) runtime.sessions.currentSession = undefined; |
|
|
|
ctx.reply('Session killed. /ls for list of sessions.') |
|
|
|
}) |
|
|
|
|
|
|
|
bot.use(ctx => { |
|
|
|
if(!sessions.currentSession) |
|
|
|
if(!runtime.sessions.currentSession) |
|
|
|
return responder.fail(`No active session. ` |
|
|
|
+ `Start one with /start or view list of sessions by sending /ls.`)(ctx); |
|
|
|
const cmd = ctx.update.message.text; |
|
|
|
const history = `${new Date().toLocaleDateString('en-IN', dateOptions)}: ${cmd}`; |
|
|
|
sessions.history.push(history); |
|
|
|
runtime.history.push(history); |
|
|
|
console.log(history); |
|
|
|
sessions.currentSession.stdin.write(cmd + EOL); |
|
|
|
runtime.sessions.currentSession.stdin.write(cmd + EOL); |
|
|
|
}); |
|
|
|
|
|
|
|
bot.startPolling(); |
|
|
|