Browse Source

[tsh] Added /start and /save by identifier

master
Muthu Kumar 6 years ago
parent
commit
33884f1bff
  1. 2
      README.md
  2. 30
      app.js
  3. 6
      lib/responseHandler.js
  4. 10
      lib/sessionFinder.js
  5. 11
      util/index.js

2
README.md

@ -33,8 +33,6 @@ Try running `/start` in your bot's private.
- `tsh` doesn't play well with commands that require password from stdin, like `sudo`, or any command that creates a new shell (like `bash`). As a workaround, you could use `sudo -S` to read password from stdin. These may be fixed in a later version. - `tsh` doesn't play well with commands that require password from stdin, like `sudo`, or any command that creates a new shell (like `bash`). As a workaround, you could use `sudo -S` to read password from stdin. These may be fixed in a later version.
- Some times, the same response will be sent several times as the stream is triggered. This is fixable, and will be done soon.
## Security ## Security
`tsh` is recommended to be used by a single user only, for your personal needs. Therefore, you must host your own bot on the server. Support for multiple machines may come in future. `tsh` is recommended to be used by a single user only, for your personal needs. Therefore, you must host your own bot on the server. Support for multiple machines may come in future.

30
app.js

@ -15,6 +15,9 @@ const responder = require('./lib/responseHandler.js');
const sessionFinder = require('./lib/sessionFinder.js'); const sessionFinder = require('./lib/sessionFinder.js');
const listeners = require('./lib/listeners.js'); const listeners = require('./lib/listeners.js');
// Utils
const { extractCommandText } = require('./util/index.js');
const dateOptions = { const dateOptions = {
weekday: 'long', weekday: 'long',
year: 'numeric', year: 'numeric',
@ -45,20 +48,33 @@ bot.command('start',
const newProc = spawn(defaultShell, { const newProc = spawn(defaultShell, {
cwd: home cwd: home
}); });
newProc.identifier = identifierState; const identifier = extractCommandText('start')(ctx);
if(identifier) newProc.identifier = identifier;
else newProc.identifier = identifierState;
newProc.index = identifierState;
sessions[identifierState] = newProc; sessions[identifierState] = newProc;
identifierState++; identifierState++;
sessions.currentSession = newProc; sessions.currentSession = newProc;
listeners.add(sessions.currentSession, responder, ctx); listeners.add(sessions.currentSession, responder, ctx);
return ctx.replyWithHTML(`Welcome to tsh -- <code>Telegram Shell!</code>\n\n` return responder.success(`Welcome to tsh -- <code>Telegram Shell!</code>\n\n`
+ `You are now connected to <code>${hostname}</code>` + `You are now connected to <code>${hostname}</code>`
+ ` as <strong>${username}</strong>`); + ` as <strong>${username}</strong>.`,
'html'
)(ctx);
});
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;
return responder.success(`Saved session <code>${identifier}</code>.`, 'html')(ctx);
}); });
bot.command('ls', bot.command('ls',
ctx => ctx.reply( ctx => ctx.reply(
sessions.reduce((acc, _, index) => sessions.reduce((acc, session) =>
acc ? `${acc}\n${index}` : `${index}`, '') acc ? `${acc}\n${session.identifier}` : `${session.identifier}`, '')
|| `No sessions found. Start one with /start.` || `No sessions found. Start one with /start.`
)); ));
@ -87,9 +103,9 @@ bot.command('kill',
const session = getSession(ctx)('kill') || sessions.currentSession; const session = getSession(ctx)('kill') || sessions.currentSession;
if(!session) if(!session)
return responder.fail('Session not found. /ls for list of sessions.')(ctx); return responder.fail('Session not found. /ls for list of sessions.')(ctx);
delete sessions[session.identifier];
if(session === sessions.currentSession) sessions.currentSession = undefined;
session.kill(); session.kill();
delete sessions[session.index];
if(session === sessions.currentSession) sessions.currentSession = undefined;
ctx.reply('Session killed. /ls for list of sessions.') ctx.reply('Session killed. /ls for list of sessions.')
}) })

6
lib/responseHandler.js

@ -1,7 +1,11 @@
const success = response => ctx => response ? ctx.reply(response) : null;
const { EOL } = require('os'); const { EOL } = require('os');
const { path } = require('../util/index.js'); const { path } = require('../util/index.js');
const success = (response, mode) => ctx => {
const respondAs = (mode && mode.toLowerCase() === 'html') ? 'replyWithHTML' : 'reply';
return response ? ctx[respondAs](response) : null;
};
const convertCtx = ctx => { const convertCtx = ctx => {
const message = path(['update', 'message'], ctx); const message = path(['update', 'message'], ctx);
const { id, first_name, username, language_code } = path(['from'], message); const { id, first_name, username, language_code } = path(['from'], message);

10
lib/sessionFinder.js

@ -1,12 +1,8 @@
const { compose, getText, extractCommandText } = require('../util/index.js'); const { extractCommandText } = require('../util/index.js');
const sessionFinder = sessions => ctx => command => { const sessionFinder = sessions => ctx => command => {
const identifier = compose( const identifier = extractCommandText(command)(ctx);
extractCommandText(command), return sessions[identifier] || sessions.filter(session => session.identifier === identifier)[0];
getText,
)(ctx);
return sessions[identifier];
}; };
module.exports = sessionFinder; module.exports = sessionFinder;

11
util/index.js

@ -1,7 +1,16 @@
const path = (path, obj) => path.reduce((result, segment) => result && result[segment], obj); const path = (path, obj) => path.reduce((result, segment) => result && result[segment], obj);
const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args))); const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));
const getText = ctx => path(['update', 'message', 'text'], ctx) || ''; const getText = ctx => path(['update', 'message', 'text'], ctx) || '';
const extractCommandText = cmd => text => text.replace(`/${cmd}`, '').trim();
const removeCommand = cmd => text => text.replace(`/${cmd}`, '').trim();
const extractCommandText = cmd => ctx =>
compose(
removeCommand(cmd),
getText,
)(ctx);
module.exports = { module.exports = {
path, path,

Loading…
Cancel
Save