119 lines
3.3 KiB
TypeScript
119 lines
3.3 KiB
TypeScript
import util from 'util';
|
|
import cprog from 'child_process';
|
|
|
|
import {
|
|
Plugin,
|
|
Configurable,
|
|
EventListener,
|
|
DependencyLoad
|
|
} from '@squeebot/core/lib/plugin';
|
|
|
|
import { IMessage, MessageResolver } from '@squeebot/core/lib/types';
|
|
|
|
import { ISqueebotCore, logger } from '@squeebot/core/lib/core';
|
|
|
|
function addCommands(plugin: UtilityPlugin, commands: any): void {
|
|
const cmds = [{
|
|
plugin: plugin.manifest.name,
|
|
name: 'evaljs',
|
|
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
|
|
if (!simplified[0]) {
|
|
return true;
|
|
}
|
|
const script = simplified.join(' ');
|
|
|
|
// Disallow child_process when shell is disallowed
|
|
if ((script.indexOf('child_process') !== -1 ||
|
|
script.indexOf('cprog') !== -1 ||
|
|
script.indexOf('fork') !== -1) &&
|
|
!plugin.config.config.allowShell) {
|
|
msg.resolve('Error: child_process is not allowed in evaljs due to security reasons.');
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
// tslint:disable-next-line: no-eval
|
|
const mesh = eval(script);
|
|
if (mesh === undefined) {
|
|
return true;
|
|
}
|
|
msg.resolve(util.format(mesh));
|
|
} catch (e) {
|
|
msg.resolve('Error: ' + e.message);
|
|
}
|
|
|
|
return true;
|
|
},
|
|
usage: '<javascript>',
|
|
description: 'Execute JavaScript in a command context',
|
|
permissions: ['system_execute'],
|
|
hidden: true
|
|
}];
|
|
|
|
if (plugin.config.config.allowShell) {
|
|
logger.warn('WARNING! Shell command execution is enabled! Make absolutely sure that there is proper authentication!');
|
|
if (process.getuid && process.getuid() === 0) {
|
|
logger.warn('NEVER run Squeebot as root! Run `useradd squeebot`! We are not responsible for possible security leaks!');
|
|
}
|
|
|
|
cmds.push({
|
|
plugin: plugin.manifest.name,
|
|
name: 'sh',
|
|
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
|
|
const stripnl = (simplified[0] !== '-n');
|
|
const cmd = simplified.slice(stripnl ? 0 : 1).join(' ');
|
|
if (!cmd) {
|
|
msg.resolve('Nothing to execute!');
|
|
return true;
|
|
}
|
|
|
|
cprog.exec(cmd, {shell: '/bin/bash'}, (error, stdout, stderr) => {
|
|
if (stdout) {
|
|
if (stripnl) { stdout = stdout.replace(/\n/g, ' ;; '); }
|
|
|
|
return msg.resolve(stdout);
|
|
}
|
|
|
|
msg.resolve('Error executing command.');
|
|
logger.error(stderr || error);
|
|
});
|
|
|
|
return true;
|
|
},
|
|
description: 'Run raw shell command',
|
|
usage: '<shell>',
|
|
hidden: true,
|
|
permissions: ['system_shell'],
|
|
});
|
|
}
|
|
|
|
commands.registerCommand(cmds);
|
|
}
|
|
|
|
@Configurable({
|
|
allowShell: false,
|
|
})
|
|
class UtilityPlugin extends Plugin {
|
|
public core: ISqueebotCore | null = null;
|
|
|
|
@DependencyLoad('simplecommands')
|
|
addCommands(cmd: any): void {
|
|
addCommands(this, cmd);
|
|
}
|
|
|
|
@EventListener('pluginUnload')
|
|
public unloadEventHandler(plugin: string | Plugin): void {
|
|
if (plugin === this.name || plugin === this) {
|
|
this.config.save().then(() =>
|
|
this.emit('pluginUnloaded', this));
|
|
}
|
|
}
|
|
|
|
initialize(): void {
|
|
this.on('core', (c: ISqueebotCore) => this.core = c);
|
|
this.emitTo('core', 'request-core', this.name);
|
|
}
|
|
}
|
|
|
|
module.exports = UtilityPlugin;
|