Added contrib "evlang", an experimental highly restricted Python code environment. It's intended to be used by untrusted users to add custom code e.g. to their crafted objects and similar. Please heed the warnings in the README file - this is experimental still and more people need to play with it and try to break it.
The system uses a hybrid blacklisting/whitelisting and AST-traversal approach to both remove dangerous builtins as well as disallow potentially exploitable python structures alltogether. Examples are while structures and attribute allocation. All advanced functionality is accessed through a set of "safe" methods on a holder object. You can extend this with your own safe methods in order to add more functionality befitting your game. The system comes with a host of examples, a few scriptable objects and complete commands for adding code to objects. At this point it's not guaranteed that all systems are safe against meddling however - notably Attributes have no locks defined on them by default (although this system does properly check Attribute lock types should they exixt). Please test and try to break - and report problems to the Issue tracker/forum as usual.
This commit is contained in:
parent
3d24ee2242
commit
58e20e2cf1
6 changed files with 1302 additions and 0 deletions
109
contrib/evlang/README
Normal file
109
contrib/evlang/README
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
|
||||
EVLANG
|
||||
|
||||
EXPERIMENTAL IMPLEMENTATION
|
||||
|
||||
Evennia contribution - Griatch 2012
|
||||
|
||||
"Evlang" is a heavily restricted version of Python intended to be used
|
||||
by regular players to code simple functionality on supporting objects.
|
||||
It's referred to as "evlang" or "evlang scripts" in order to
|
||||
differentiate from Evennia's normal (and unrelated) "Scripts".
|
||||
|
||||
WARNING:
|
||||
Restricted python execution is a tricky art, and this module -is-
|
||||
partly based on blacklisting techniques, which might be vulnerable to
|
||||
new venues of attack opening up in the future (or existing ones we've
|
||||
missed). Whereas I/we know of no obvious exploits to this, it is no
|
||||
guarantee. If you are paranoid about security, consider also using
|
||||
secondary defences on the OS level such as a jail and highly
|
||||
restricted execution abilities for the twisted process. So in short,
|
||||
this should work fine, but use it at your own risk. You have been
|
||||
warned.
|
||||
|
||||
An Evennia server with Evlang will, once set up, minimally consist of
|
||||
the following components:
|
||||
|
||||
- The evlang parser (bottom of evlang.py). This combines
|
||||
regular removal of dangerous modules/builtins with AST-traversal.
|
||||
it implements a limited_exec() function.
|
||||
- The Evlang handler (top of evlang.py). This handler is the Evennia
|
||||
entry point. It should be added to objects that should support
|
||||
evlang-scripting.
|
||||
- A custom object typeclass. This must set up the Evlang handler
|
||||
and store a few critical Attributes on itself for book-keeping.
|
||||
The object will probably also overload some of its hooks to
|
||||
call the correct evlang script at the proper time
|
||||
- Command(s) for adding code to supporting objects
|
||||
- Optional expanded "safe" methods/objects to include in the
|
||||
execution environment. These are defined in settings (see
|
||||
header of evlang.py for more info).
|
||||
|
||||
You can set this up easily to try things out by using the included
|
||||
examples:
|
||||
|
||||
Quick Example Install
|
||||
---------------------
|
||||
|
||||
This is a quick test-setup using the example objects and commands.
|
||||
|
||||
1) If you haven't already, make sure you are able to overload the
|
||||
default cmdset: Copy game/gamesrc/commands/examples/cmdset.py up one level,
|
||||
then change settings.CMDSET_DEFAULT to point to DefaultCmdSet in your newly copied module.
|
||||
Restart the server and check so the default commands still work.
|
||||
2) Import and add
|
||||
contrib.evlang.command.CmdCode
|
||||
and
|
||||
contrib.evlang.examples.CmdCraftScriptable
|
||||
to your default command set. Reload server.
|
||||
|
||||
That's it, really. You should now have two new commands available,
|
||||
@craftscriptable and @code. The first one is a simple "crafting-like"
|
||||
command that will create an object of type
|
||||
contrib.evlang.examples.CraftedScriptableObject while setting it up
|
||||
with some basic scripting slots.
|
||||
|
||||
Try it now:
|
||||
|
||||
@craftscriptable crate
|
||||
|
||||
You create a simple "crate" object in your current location. You can
|
||||
use @code to see which "code types" it will accept.
|
||||
|
||||
@code crate
|
||||
|
||||
You should see a list with "drop", "get" and "look", each without
|
||||
anything assigned to them. If you look at how CraftedScriptableObject
|
||||
is defined you will find that these "command types" (you can think of
|
||||
them as slots where custom code can be put) are tied to the at_get,
|
||||
at_drop and at_desc hooks respecively - this means Evlang scripts put
|
||||
in the respective slots will ttrigger at the appropriate time.
|
||||
|
||||
There are a few "safe" objects made available out of the box.
|
||||
|
||||
self - reference to object the Evlang handler is defined on
|
||||
here - shortcut for self.location
|
||||
caller - reference back to the one triggering the script
|
||||
scripter - reference to the one creating the script (set by @code)
|
||||
|
||||
There is also the 'evl' object that defines "safe" methods to use.
|
||||
evl.msg(string, obj=None) # default is the send to caller
|
||||
evl.msg_contents(string, obj=None) # default is to send to all except caller
|
||||
delay(delay, function, *args, **kwargs)
|
||||
attr(obj, attrname=None, attrvalue=None, delete=False) # lock-checking attribute accesser
|
||||
list() # display all available methods on evl, with docstrings (including your custom additions)
|
||||
|
||||
These all return True after successful execution, which makes
|
||||
especially the msg* functions easier to use in a conditional. Let's
|
||||
try it.
|
||||
|
||||
@code crate/look = if caller.key=='Superman' and evl.msg("Your gaze burns a small hole.") or evl.msg("Looks robust!")
|
||||
|
||||
Now look at the crate. :)
|
||||
|
||||
You can (in evlang) use evl.list() to get a list of all methods currently stored on the evl object. For testing, let's
|
||||
use the same look slot on the crate again. But this time we'll use the /debug mode of @code, which means the script
|
||||
will be auto-run immediately and we don't have to look at the create to get a result when developing.
|
||||
|
||||
@code/debug create/look = evl.msg(evl.list())
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue