-
Notifications
You must be signed in to change notification settings - Fork 2
Extension: pack
Compile messages into data packs and resource packs.
-
timeout
: The maximum number of seconds that builds are allowed to run for. Defaults to 5 seconds. -
stacktraces
: A boolean indicating if the bot should reply with the full exception tracebacks. Defaults to false. -
<beet config option>
: Edit thebeet
configuration used by the bot.
The extension provides a single pack
command. The command takes an optional name
argument that's used for changing the name of the output data pack or resource pack. The command is available to all users.
Examples usage:
.pack
`@function demo:foo`
```
say hello
```
By default, the zipfile is named after the username of the message author. You can change it by providing a name explicitly:
.pack greeting
`@function demo:foo`
```
say hello
```
The message is interpreted by lectern
to extract data pack and resource pack fragments. Note that the extension doesn't run the build on the main thread so the bot should remain responsive even if someone is generating huge data packs or resource packs.
You can use beet
plugins to customize the build process. For example, if you want to use the syntactic extensions provided by the beet.contrib.hangman
plugin you can configure the bot like this:
{
"command_prefix": ".",
"extensions": [
{
"name": "commanderbot.ext.pack",
"options": {
"pipeline": ["beet.contrib.hangman"],
"meta": {
"hangman": {
"match": ["*"]
}
}
}
}
]
}
This allows the bot to understand messages like these:
.pack
`@function demo:foo`
```
execute as @a run commands
say hello
say world
```
Note that you can use the extend
option to separate the beet
config into its own file. This also allows the bot to automatically reload the beet
config if you change it.
// bot.json
{
"command_prefix": ".",
"extensions": [
{
"name": "commanderbot.ext.pack",
"options": {
"extend": ["beet.json"]
}
}
]
}
// beet.json
{
"pipeline": ["beet.contrib.hangman"],
"meta": {
"hangman": {
"match": ["*"]
}
}
}
To turn messages into data packs and resource packs, the command feeds untrusted input into the beet
pipeline. This is usually fine, however lectern
has a @require
directive that can include extra plugins dynamically. If you decide to enable it, you can restrict the plugins available by specifying the whitelist
option:
{
"command_prefix": ".",
"extensions": [
{
"name": "commanderbot.ext.pack",
"options": {
"whitelist": [
"lectern.contrib.require",
"commanderbot.ext.pack.pack_generate"
],
"require": ["lectern.contrib.require"]
}
}
]
}
Note that you'll always need to whitelist commanderbot.ext.pack.pack_generate
as it's required by the bot. Of course if you add other plugins to the pipeline you need to add them to the whitelist as well.
{
"command_prefix": ".",
"extensions": [
{
"name": "commanderbot.ext.pack",
"options": {
"whitelist": [
"lectern.contrib.require",
"beet.contrib.hangman",
"commanderbot.ext.pack.pack_generate"
],
"require": ["lectern.contrib.require"],
"pipeline": ["beet.contrib.hangman"],
"meta": {
"hangman": {
"match": ["*"]
}
}
}
}
]
}
The beet.contrib.render
plugin lets you process messages with Jinja. This can be really useful but really unsafe too. By default there's no mitigation that prevents Jinja from running malicious input. Therefore, you should only activate templates with the beet.contrib.template_sandbox
plugin to enable the Jinja Sandbox.
{
"command_prefix": ".",
"extensions": [
{
"name": "commanderbot.ext.pack",
"options": {
"require": ["beet.contrib.template_sandbox"],
"pipeline": ["beet.contrib.render"],
"meta": {
"render": {
"data_pack": {
"functions": ["*"]
}
}
}
}
}
]
}
The beet.contrib.template_sandbox
plugin resets the template environment so it must be executed before the beet.contrib.render
plugin by using the require
option.
With the sandbox in place, everything should now be fine. The only thing to watch out for is that people can still try to slow the host machine down by generating huge data packs or resource packs:
.pack
`@function demo:foo`
```
#!for i in range(100000)
#!for j in range(100000)
say {{ i + j }}
#!endfor
#!endfor
```
You can adjust the timeout
option to stop processing abusive messages:
{
"command_prefix": ".",
"extensions": [
{
"name": "commanderbot.ext.pack",
"options": {
"timeout": 3
}
}
]
}
By default the build stops if a message takes more than 5 seconds to process. When adjusting the timeout keep in mind that lectern
supports including files from urls so if you care about being able to use this feature you should use a timeout that gives lectern
enough time to download remote files.
It's worth mentioning that everything here also applies if you're using lectern.contrib.define
or lectern.contrib.script
. These two plugins add directives that use Jinja so you should enable the sandbox if you use them with a public-facing bot.
The following example shows how to enable templating alongside other features that might be interesting for processing messages. It uses a custom timeout and a separate beet.json
for configuring the pipeline.
// bot.json
{
"command_prefix": ".",
"extensions": [
{
"name": "commanderbot.ext.pack",
"options": {
"timeout": 3,
"extend": ["beet.json"]
}
}
]
}
// beet.json
{
"require": [
"beet.contrib.template_sandbox",
"beet.contrib.inline_function",
"beet.contrib.inline_function_tag",
"beet.contrib.dundervar",
"lectern.contrib.relative_location",
"lectern.contrib.define",
"lectern.contrib.script"
],
"pipeline": [
"beet.contrib.render",
"beet.contrib.hangman",
"beet.contrib.relative_function_path",
"beet.contrib.scoreboard"
],
"meta": {
"render": {
"data_pack": {
"functions": ["*"]
}
},
"hangman": {
"match": ["*"]
}
}
}
First, in the require
option we're using the template sandbox to make it safe to enable templating, as well as plugins that provide #!function
and #!tag
in templates, __dunder__
interpolation, resource locations without namespaces @function foo
, and the @define
and @script
directives. In the pipeline, we start by rendering templates, then we fold hanging indents in function files with the hangman
plugin, we resolve relative function paths, and finally the scoreboard
plugin takes care of adding objectives generated with generate_objective()
to the data pack.
If you want to enable the @require
directive you should configure the whitelist
. The whitelist
needs to include all the plugins specified in the config file, plus the one used by the bot.
// beet.json
{
"whitelist": [
"beet.contrib.template_sandbox",
"beet.contrib.inline_function",
"beet.contrib.inline_function_tag",
"beet.contrib.dundervar",
"lectern.contrib.relative_location",
"lectern.contrib.require",
"lectern.contrib.define",
"lectern.contrib.script",
"beet.contrib.render",
"beet.contrib.hangman",
"beet.contrib.scoreboard",
"beet.contrib.relative_function_path",
"commanderbot.ext.pack.pack_generate",
"beet.contrib.yellow_shulker_box"
],
"require": [
"beet.contrib.template_sandbox",
"beet.contrib.inline_function",
"beet.contrib.inline_function_tag",
"beet.contrib.dundervar",
"lectern.contrib.relative_location",
"lectern.contrib.require",
"lectern.contrib.define",
"lectern.contrib.script"
],
"pipeline": [
"beet.contrib.render",
"beet.contrib.hangman",
"beet.contrib.relative_function_path",
"beet.contrib.scoreboard"
],
"meta": {
"render": {
"data_pack": {
"functions": ["*"]
}
},
"hangman": {
"match": ["*"]
}
}
}