2015-12-22 19:47:02 +01:00
|
|
|
"""
|
|
|
|
exec.py: Provides commands for executing raw code and debugging PyLink.
|
|
|
|
"""
|
2017-03-12 07:47:07 +01:00
|
|
|
import pprint
|
2015-12-22 19:47:02 +01:00
|
|
|
|
2016-06-21 03:18:54 +02:00
|
|
|
from pylinkirc import utils, world
|
|
|
|
from pylinkirc.log import log
|
2016-12-10 06:42:18 +01:00
|
|
|
from pylinkirc.coremods import permissions
|
2015-08-26 05:46:47 +02:00
|
|
|
|
2015-12-29 20:03:45 +01:00
|
|
|
# These imports are not strictly necessary, but make the following modules
|
|
|
|
# easier to access through eval and exec.
|
|
|
|
import threading
|
|
|
|
import re
|
|
|
|
import time
|
2016-07-24 20:51:44 +02:00
|
|
|
import pylinkirc
|
|
|
|
import importlib
|
2015-09-27 21:15:10 +02:00
|
|
|
|
2017-02-06 05:26:40 +01:00
|
|
|
exec_locals_dict = {}
|
2017-03-12 07:47:07 +01:00
|
|
|
PPRINT_MAX_LINES = 20
|
|
|
|
PPRINT_WIDTH = 200
|
2017-02-06 05:26:40 +01:00
|
|
|
|
|
|
|
def _exec(irc, source, args, locals_dict=None):
|
2015-08-26 05:46:47 +02:00
|
|
|
"""<code>
|
|
|
|
|
2015-12-22 19:41:42 +01:00
|
|
|
Admin-only. Executes <code> in the current PyLink instance. This command performs backslash escaping of characters, so things like \\n and \\ will work.
|
2016-12-10 06:42:18 +01:00
|
|
|
|
2015-08-26 05:46:47 +02:00
|
|
|
\x02**WARNING: THIS CAN BE DANGEROUS IF USED IMPROPERLY!**\x02"""
|
2016-12-10 06:42:18 +01:00
|
|
|
permissions.checkPermissions(irc, source, ['exec.exec'])
|
2015-12-22 19:41:42 +01:00
|
|
|
|
|
|
|
# Allow using \n in the code, while escaping backslashes correctly otherwise.
|
|
|
|
args = bytes(' '.join(args), 'utf-8').decode("unicode_escape")
|
2015-08-26 05:46:47 +02:00
|
|
|
if not args.strip():
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply('No code entered!')
|
2015-08-26 05:46:47 +02:00
|
|
|
return
|
2015-12-22 19:41:42 +01:00
|
|
|
|
|
|
|
log.info('(%s) Executing %r for %s', irc.name, args,
|
2017-06-30 08:01:39 +02:00
|
|
|
irc.get_hostmask(source))
|
2017-02-06 05:26:40 +01:00
|
|
|
if locals_dict is None:
|
|
|
|
locals_dict = locals()
|
2017-03-05 06:59:42 +01:00
|
|
|
else:
|
|
|
|
# Add irc, source, and args to the given locals_dict, to allow basic things like irc.reply()
|
|
|
|
# to still work.
|
|
|
|
locals_dict['irc'] = irc
|
|
|
|
locals_dict['source'] = source
|
|
|
|
locals_dict['args'] = args
|
2017-02-06 05:26:40 +01:00
|
|
|
|
|
|
|
exec(args, globals(), locals_dict)
|
2015-12-22 19:41:42 +01:00
|
|
|
|
2017-02-06 05:14:30 +01:00
|
|
|
irc.reply("Done.")
|
2015-08-26 05:46:47 +02:00
|
|
|
utils.add_cmd(_exec, 'exec')
|
2015-09-19 19:39:05 +02:00
|
|
|
|
2017-02-06 05:26:40 +01:00
|
|
|
@utils.add_cmd
|
|
|
|
def iexec(irc, source, args):
|
|
|
|
"""<code>
|
|
|
|
|
2017-03-05 06:59:42 +01:00
|
|
|
Admin-only. Executes <code> in the current PyLink instance with a persistent, isolated
|
2017-02-06 05:26:40 +01:00
|
|
|
locals scope (world.plugins['exec'].exec_local_dict).
|
|
|
|
|
2017-03-05 06:59:42 +01:00
|
|
|
Note: irc, source, and args are added into this locals dict to allow things like irc.reply()
|
|
|
|
to still work.
|
|
|
|
|
2017-02-06 05:26:40 +01:00
|
|
|
\x02**WARNING: THIS CAN BE DANGEROUS IF USED IMPROPERLY!**\x02
|
|
|
|
"""
|
|
|
|
_exec(irc, source, args, locals_dict=exec_locals_dict)
|
|
|
|
|
2017-03-12 07:47:07 +01:00
|
|
|
def _eval(irc, source, args, locals_dict=None, pretty_print=False):
|
2015-09-19 19:39:05 +02:00
|
|
|
"""<Python expression>
|
|
|
|
|
|
|
|
Admin-only. Evaluates the given Python expression and returns the result.
|
2016-12-10 06:42:18 +01:00
|
|
|
|
2015-09-19 19:39:05 +02:00
|
|
|
\x02**WARNING: THIS CAN BE DANGEROUS IF USED IMPROPERLY!**\x02"""
|
2016-12-10 06:42:18 +01:00
|
|
|
permissions.checkPermissions(irc, source, ['exec.eval'])
|
2015-12-22 19:47:02 +01:00
|
|
|
|
2015-09-19 19:39:05 +02:00
|
|
|
args = ' '.join(args)
|
|
|
|
if not args.strip():
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply('No code entered!')
|
2015-09-19 19:39:05 +02:00
|
|
|
return
|
2015-12-22 19:47:02 +01:00
|
|
|
|
2017-03-05 07:04:48 +01:00
|
|
|
if locals_dict is None:
|
|
|
|
locals_dict = locals()
|
|
|
|
else:
|
|
|
|
# Add irc, source, and args to the given locals_dict, to allow basic things like irc.reply()
|
|
|
|
# to still work.
|
|
|
|
locals_dict['irc'] = irc
|
|
|
|
locals_dict['source'] = source
|
|
|
|
locals_dict['args'] = args
|
|
|
|
|
2015-12-22 19:47:02 +01:00
|
|
|
log.info('(%s) Evaluating %r for %s', irc.name, args,
|
2017-06-30 08:01:39 +02:00
|
|
|
irc.get_hostmask(source))
|
2017-03-12 07:47:07 +01:00
|
|
|
|
|
|
|
result = eval(args, globals(), locals_dict)
|
|
|
|
|
|
|
|
if pretty_print:
|
|
|
|
lines = pprint.pformat(result, width=PPRINT_WIDTH, compact=True).splitlines()
|
|
|
|
for line in lines[:PPRINT_MAX_LINES]:
|
|
|
|
irc.reply(line)
|
|
|
|
if len(lines) > PPRINT_MAX_LINES:
|
|
|
|
irc.reply('Suppressing %s more line(s) of output.' % (len(lines) - PPRINT_MAX_LINES))
|
|
|
|
else:
|
|
|
|
irc.reply(repr(result))
|
|
|
|
|
2015-09-19 19:39:05 +02:00
|
|
|
utils.add_cmd(_eval, 'eval')
|
2015-12-22 19:47:02 +01:00
|
|
|
|
2017-03-12 07:47:07 +01:00
|
|
|
@utils.add_cmd
|
|
|
|
def peval(irc, source, args):
|
|
|
|
"""<Python expression>
|
|
|
|
|
|
|
|
Admin-only. This command is the same as 'eval', except that results are pretty formatted.
|
|
|
|
|
|
|
|
\x02**WARNING: THIS CAN BE DANGEROUS IF USED IMPROPERLY!**\x02
|
|
|
|
"""
|
|
|
|
_eval(irc, source, args, pretty_print=True)
|
|
|
|
|
2017-03-05 07:04:48 +01:00
|
|
|
@utils.add_cmd
|
|
|
|
def ieval(irc, source, args):
|
|
|
|
"""<Python expression>
|
|
|
|
|
|
|
|
Admin-only. Evaluates the given Python expression using a persistent, isolated
|
|
|
|
locals scope (world.plugins['exec'].exec_local_dict).
|
|
|
|
|
|
|
|
Note: irc, source, and args are added into this locals dict to allow things like irc.reply()
|
|
|
|
to still work.
|
|
|
|
|
|
|
|
\x02**WARNING: THIS CAN BE DANGEROUS IF USED IMPROPERLY!**\x02
|
|
|
|
"""
|
|
|
|
_eval(irc, source, args, locals_dict=exec_locals_dict)
|
|
|
|
|
2017-03-12 07:47:07 +01:00
|
|
|
@utils.add_cmd
|
|
|
|
def pieval(irc, source, args):
|
|
|
|
"""<Python expression>
|
|
|
|
|
|
|
|
Admin-only. This command is the same as 'ieval', except that results are pretty formatted.
|
|
|
|
|
|
|
|
\x02**WARNING: THIS CAN BE DANGEROUS IF USED IMPROPERLY!**\x02
|
|
|
|
"""
|
|
|
|
_eval(irc, source, args, locals_dict=exec_locals_dict, pretty_print=True)
|
|
|
|
|
2015-12-22 19:47:02 +01:00
|
|
|
@utils.add_cmd
|
|
|
|
def raw(irc, source, args):
|
|
|
|
"""<text>
|
|
|
|
|
|
|
|
Admin-only. Sends raw text to the uplink IRC server.
|
2016-12-10 06:42:56 +01:00
|
|
|
|
2015-12-22 19:47:02 +01:00
|
|
|
\x02**WARNING: THIS CAN BREAK YOUR NETWORK IF USED IMPROPERLY!**\x02"""
|
2016-12-10 06:42:18 +01:00
|
|
|
permissions.checkPermissions(irc, source, ['exec.raw'])
|
2015-12-22 19:47:02 +01:00
|
|
|
|
|
|
|
args = ' '.join(args)
|
|
|
|
if not args.strip():
|
|
|
|
irc.reply('No text entered!')
|
|
|
|
return
|
|
|
|
|
2016-11-08 06:25:57 +01:00
|
|
|
log.debug('(%s) Sending raw text %r to IRC for %s', irc.name, args,
|
2017-06-30 08:01:39 +02:00
|
|
|
irc.get_hostmask(source))
|
2015-12-22 19:47:02 +01:00
|
|
|
irc.send(args)
|
|
|
|
|
|
|
|
irc.reply("Done.")
|
|
|
|
|
|
|
|
@utils.add_cmd
|
|
|
|
def inject(irc, source, args):
|
|
|
|
"""<text>
|
|
|
|
|
|
|
|
Admin-only. Injects raw text into the running PyLink protocol module, replying with the hook data returned.
|
2016-12-10 06:42:56 +01:00
|
|
|
|
2015-12-22 19:47:02 +01:00
|
|
|
\x02**WARNING: THIS CAN BREAK YOUR NETWORK IF USED IMPROPERLY!**\x02"""
|
2016-12-10 06:42:18 +01:00
|
|
|
permissions.checkPermissions(irc, source, ['exec.inject'])
|
2015-12-22 19:47:02 +01:00
|
|
|
|
|
|
|
args = ' '.join(args)
|
|
|
|
if not args.strip():
|
|
|
|
irc.reply('No text entered!')
|
|
|
|
return
|
|
|
|
|
|
|
|
log.info('(%s) Injecting raw text %r into protocol module for %s', irc.name,
|
2017-06-30 08:01:39 +02:00
|
|
|
args, irc.get_hostmask(source))
|
2015-12-22 19:47:02 +01:00
|
|
|
irc.reply(irc.runline(args))
|