PCXCogs
PCXCogs copied to clipboard
Template engine edited to use Jinja2
Hi,
based on #70 and my own ideas to make some cool channel names, i wanted to edit the template engine. But while it was easier to just implement the Jinja2 rendering instead of understanding and editing the existing template engine, i choose that way.
I also tested this feature on my own discord and used it without a problem. For an example this is some nice stuff that is now doable. Note: i also include the whole member object and the datetime.
{% set ns = namespace(isGame=false, isSpotify=false, activityName='') %}
{% for activity in member.activities %}
{% if not ns.isGame and not ns.isSpotify %}
{% if activity.type|string == "ActivityType.playing" %}
{% set ns.isGame = true %}
{% set ns.activityName = activity.name %}
{% set ns.Game = activity %}
{% elif activity.type|string == "ActivityType.listening" and "Spotify" in activity.name %}
{% set ns.isSpotify = true %}
{% set ns.Spotify = activity %}
{% endif %}
{% endif %}
{% endfor %}
{% if member.premium_since %}
⭐ VIP-Lounge ⭐
{% else %}
{% if ns.isGame %}
{% if ns.activityName == "League of Legends" %}
{{ ["Demacias Festung 🏰", "Noxus' Schlachtfeld ⚔️", "Piltover's Hightech-Labor 🔧", "Zauns Winkelgasse 🔬", "Ionias Geisterwälder 🌲", "Freljords Eishöhle ❄️", "Schatteninseln' Nebelbucht 🌫️", "Shurimas Sonnenpyramiden 🔺", "Bandle Citys Schmuckladen 🎁", "Bilgewasser's Hafen 🚢", "Targons Tempel ⛰️"]|random }}
{% else %}
{{ ns.activityName }}
{% endif %}
{% elif ns.isSpotify %}
{{ ["Coachella 🎵", "Berghain 🎧", "Tomorrowland 🎶", "Lollapalooza 🎸", "Burning Man 🎷", "Rock am Ring 🎤", "Ultra Music 🦑", "KitKat 🎼"]|random }} feat. {{ns.Spotify.artists[0]}}
{% else %}
{{ username }}s {{ ["Räumchen 🏠", "Ecke 📘", "Raum 🚪", "Kabinett 📃", "Salon 🛋️", "Sphäre 🌌", "Galerie 🖼️", "Tempel 🏛️", "Welt 🌍", "Paradies 🌴", "Hütte 🏡", "Labor 🔬", "Schmiede 🔨", "Garten 🌷", "Ufer 🏞️", "Bude 🏚️", "Nest 🐦", "Stube 🛋️", "Foyer 🏢", "Grotte 🕳️"]|random }}
{% endif %}
{% endif %}
{% if dupenum > 1 %} #{{dupenum}}{% endif %}
What is your opinion on this?
When making my template engine, it was based on a mix of Jinja2 and Mustache. Ultimately, I wanted to use Jinja2, but couldn't figure out how to secure it. So, I am more than happy to switch to using this, I just need to verify somehow that the admin creating a template doesn't somehow do low level stuff. It's been a while, I don't remember the details, but I knew that Jinja2 didn't guarantee safety on untrusted templates. I recall being able to load any file on the host system? Not sure.
We will also have to make sure the template tests all pass, and if they don't, decide on a case by case basis if the slight formatting change in the result is fine and update the test cases.
Finally, we will have to see if the default templates (username and game) need to change, and if we need to do a search/replace of any custom templates that people are using. My guess is that since my template was a subset of Jinja2/Mustache, we shouldn't need any changes. Same with the test cases.
Your example is super cool though! We might now need a way to recall raw templates, like the custom command cog does, for easier modification.
Yeah i'm aware of the security standpoint thats why i choose to use the sandboxed environment, to which my understanding, makes sure that a passed template can execute unsafe functions. The only thing that might be unsafe is to hand over the whole Member object. Maybe it would be better to just add some desirable information of the member. But again the sandbox should not allow to execute unsafe stuff with the member.
Regarding the test cases you are right, i should look more deeply into that and create some more of these to make sure everything behaves as intended. I will take a look into that.
For the standard ones and and existing templates: These shouldn't need any update because the still work with the Jinja2 engine.
I think we should use ImmutableSandboxedEnvironment instead of SandboxedEnvironment, just to be on the safe side. But also probably just extract out specific member attributes that are useful. Make a mock member object (or a dict thing) and fill it with whatever member object details we want visible.
Additionally, it might be beneficial to make our own Sandbox Environment based on ImmutableSandboxedEnvironment so that we can limit power and other operations: https://jinja.palletsprojects.com/en/3.0.x/sandbox/#operator-intercepting
I'm thinking, can someone do something stupid like for x in range( <very large number> ) and then it causes the renderer/bot to slow down when it's calculating that? You could even nest a bunch of for loops inside each other to really slow it down exponentially. I have no idea how to detect and limit that... unless the sandbox has a default timeout thing? That would be nice.