Telegram is a popular messaging app that offers a variety of solid clients and features, including chatbots. In this blog post, we will explore how to create a Telegram chatbot that we can communicate with, in Rye language - yeah, we’re fans :=).
Starting with an Echo Bot
Our first step in creating a Telegram chatbot will be to create a simple Echo bot. An Echo bot simply echoes back whatever message it receives. This is a good starting point for learning how to create more complex bots.
Setting up a new bot in Telegram involves interacting with the BotFather on Telegram itself to get a token, which you’ll save in a .token
file.
Rye uses Go’s telegram-bot-api library quite direct. With a few helper functions the example code could be shorter and more high level, but this better shows us what is going on behind the scenes.
So we load the API token, create an instance of the Telegram-bot and define its on-update method. In it we parse the ‘Message’ out of the JSON message we received, and Chat ID out of that. We need ID to create a reply message, with Text the same as it was in the incoming message. And we send it.
Exposing Rye context through Telegram
That worked … Now we want to create a context in Rye and let us chat inside that context. Our context shell below, features 3 demonstrational functions, but Rye can do a lot of things, so we could make a context that does something useful on a remote computer, on remote Raspberry Pi even. Like report us some measurements, turn on the heating, feed the cat :)
To make the important parts pop out more, we created two quite self-explanatory helper functions: extract-message and reply.
Our business logic is in a function called produce-reply. It loads the input into Rye datastructure, prints it (so we can see what is going on on our server side) and does the loaded code, but inside a context shell.
But our code has a huge problem. The context we created is linked to its parent context, so we can basically call any Rye functions through the Telegram and not just the functions inside the context!
If a bad actor gets access to your bot it can basically do anything on your remote computer. At least anything you build your Rye instance with. You can not include database, HTTP functions, you can disable all IO functions at build time, but I still don’t recommend it. If nothing else a bad actor can run a forever loop on your instance.
So why did I create this example then? To highlight the inherent security risk and also because this is a step towars what we want.
Detour: Contexts as first class values
Like Rye code is just Rye data, Context (scope) in which Rye code is evaluated is just another Rye datatype. Context is similar to a dictionary, with a optional link to a parent context.
Function context creates a context linked to a current context. But we can change the link and we can also create a context with no link with function isolate.
So let’s use the isolate functions. But, we will find out … “It’s just not that simple” :)
So in this rare case “we can have our cake and eat it too” …
Securing the Bot with Isolated Contexts
The major flaw of the previous bot — the ability to execute any Rye command — can be solved by what we learned in the previous section. Let’s put this to work
To reiterate: By using Rye’s isolate
function instead of context
, and fnc
with parent-ctx
we ensured that the bot execute strictly just the functions in a given context. And those functions can use Rye libraries to do useful things.
But what if we want to pull specific Rye functions (whitelist) back in? We can do this without a problem. We can construct a context or a separate hierarchy of contexts as freely as we want to. More about that in some next blogpost …
Visit our website, reddit groupreddit group or Rye’s github for more.