Browse Source

[mvc] Proof of concept

master
Muthu Kumar 6 years ago
parent
commit
77a2978318
  1. 94
      app.js
  2. 3
      lib/process.js
  3. 34
      lib/responseHandler.js
  4. 10
      lib/validator.js
  5. 2
      package.json

94
app.js

@ -1,14 +1,92 @@
const { spawn } = require('child_process');
const { EOL } = require('os');
const Telegraf = require('telegraf');
const config = require('./config')
const { path } = require('./util/index.js');
const config = require('./config.js');
const validator = require('./lib/validator');
const responder = require('./lib/responseHandler.js');
const dateOptions = {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
};
const bot = new Telegraf(config.botApiKey);
const sessions = [];
sessions.history = [];
bot.use((ctx, next) =>
validator(ctx)
.then(next)
.catch(responder.fail(
`Username Not authenticated!`
)));
bot.command('start',
ctx => {
ctx.replyWithHTML('Welcome to tsh -- <code>Telegram Shell!</code>');
const newProc = spawn('bash', {
cwd: '/home'
});
newProc.stdout.setEncoding('utf8');
sessions.push(newProc);
sessions.currentSession = newProc;
});
bot.command('ls',
ctx => ctx.reply(
sessions.reduce((acc, _, index) =>
acc ? `${acc}\n${index}` : `${index}`, '')
|| `No sessions found. Start one with /start.`
));
bot.command('attach',
ctx => {
const text = path(['update', 'message', 'text'], ctx);
const sessionIndex = parseInt(text.replace('/attach ', '').trim());
if(Number.isNaN(sessionIndex) || !sessions[sessionIndex]) return responder.fail('Session not found. /ls for list of sessions')(ctx);
sessions.currentSession = sessions[sessionIndex];
return responder.success(`Reattached to shell ${sessionIndex}`)(ctx);
});
const bot = new Telegraf(config.apiKey)
bot.command('detach',
ctx => {
const text = path(['update', 'message', 'text'], ctx);
const sessionIndex = parseInt(text.replace('/detach ', '').trim());
const currentSession = text.trim() === '/detach' ? sessions.currentSession : sessions[sessionIndex];
if(!currentSession) return responder.fail('Session not found. /ls for list of sessions.')(ctx);
sessions.currentSession = undefined;
return responder.success(`Detached from shell ${sessionIndex}`)(ctx);
});
bot.command('start', ctx => {
return ctx.reply('Bot succesfully started!');
})
bot.command('kill',
ctx => {
const text = path(['update', 'message', 'text'], ctx);
const sessionIndex = parseInt(text.replace('/kill ', '').trim());
if(Number.isNaN(sessionIndex) || !sessions[sessionIndex]) return responder.fail('Session not found. /ls for list of sessions.')(ctx);
const disconnect = sessions[sessionIndex];
delete sessions[sessionIndex];
if(disconnect === sessions.currentSession) sessions.currentSession = undefined;
disconnect.kill();
ctx.reply('Session killed. /ls for list of sessions.')
})
bot.hears('hi', ctx => {
return ctx.reply('Hey!, How are you?');
})
bot.use(ctx => {
if(!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);
console.log(history);
sessions.currentSession.stdin.write(cmd + EOL);
sessions.currentSession.stdout.on('data', d => responder.success(d)(ctx));
sessions.currentSession.stdout.on('error', e => responder.success(e)(ctx));
});
bot.startPolling();
console.log(`Polling for updates.`);

3
lib/process.js

@ -0,0 +1,3 @@
const process = ctx => {
const { text } = ctx.update.message;
}

34
lib/responseHandler.js

@ -0,0 +1,34 @@
const success = response => ctx => response ? ctx.reply(response) : null;
const { EOL } = require('os');
const { path } = require('../util/index.js');
const convertCtx = ctx => {
const message = path(['update', 'message'], ctx);
const { id, first_name, username, language_code } = path(['from'], message);
const { text } = message;
return JSON.stringify({
id,
first_name,
username,
language_code,
text,
}, null, 2);
};
const fail = response => ctx => {
if(!response
|| !path(['update', 'message'], ctx)
) return;
console.log(
EOL,
response,
EOL,
`With context: `,
convertCtx(ctx),
);
return ctx.reply(response);
};
module.exports = {
success, fail,
};

10
lib/validator.js

@ -0,0 +1,10 @@
const { path } = require('../util/index.js');
const config = require('../config.js');
const validate =
ctx => {
if(!path(['update', 'message', 'from', 'id'], ctx)) return Promise.reject(ctx);
return (ctx.update.message.from.id === config.masterID) ? Promise.resolve(ctx) : Promise.reject(ctx);
}
module.exports = validate;

2
package.json

@ -1,6 +1,6 @@
{
"name": "@codefeathers/tsh",
"version": "0.0.1",
"version": "0.0.2",
"description": "Telegram Shell -- complete remote shell access over Telegram bot API",
"main": "app.js",
"dependencies": {

Loading…
Cancel
Save