a persistent little bot: IRC part 3

what if the bot got ... memory? filesystem time!

[with an IRC buffer open in #lodef]

> lodefbot: what is rfc2821?

ok, last time we created a bot. it didn't do much, you could ask it
things and tell it things, but it had a fatal flaw: all that data
went away when you restarted the program.

> lodefbot: set episode3 to in progress

[switch to terminal and ctrl-c the process]

poof; gone forever. we're going to need to save this somewhere
if we want it to stick around.

    (fn handle [line]
      (match (line:match "lodefbot: what is (.+)%?")
        term (print (string.format "PRIVMSG #lodef :%s is %s"
                                   term (get term))))
      (match (line:match "lodefbot: set (%S+) to (.+)")
        (term def) (do (set! term def)
                       (print "PRIVMSG #lodef :ok!"))))

of course, these functions don't exist yet, so let's write them:

    (fn set! [term definition]
      (with-open [f (assert (io.open (.. "data/" term) :w))]
        (f:write definition)))

    (fn get [term]
      (match (io.open (.. "data/" term))
        f (with-open [f f] (f:read))
        _ "unknown"))

if you're paying close attention, this might feel kind of watching a
horror film when you know something terrible is about to happen.
instead of "don't open that door!" it's "don't trust that file path!"

[switch to the shell again, ctrl-c and restart]

because of course, you can do devious things like:

> lodefbot: what is ../bot.fnl?

in this case IRC's limitations prevent us from leaking more than the
first line, but it won't stop us from overwriting an existing file
anywhere on the disk. I don't want to demonstrate that right now
because it's very scary and we might have young children watching the
show, but you get the idea.

obviously the fix is to just validate the term name, right? ok,
fine. that will solve this problem. but there's such a thing as a
defense in depth. what about a solution that would make this kind of
leak altogether impossible?

sounds too good to be true, right? it's actually not that difficult,
we just need to reframe our thinking. we'll get to the good parts in
the next episode.