Last Updated: February 25, 2016
·
1.16K
· destructuring

Rough outline of an irssi znc auto-opt plugin

I wrote a quick irssi plugin that lets me run a few irssi sessions in tmux on various cloud hosts that op each other using the auto-op protocol made popular by the znc bouncer. I can tmux in and start chatting as any of them.

ZNC Auto-op Protocol

The ZNC auto-op protocol is a sequence of IRC notices.

bot: !ZNCAO CHALLENGE uOceZDNtXOv36VJXc5Dt0Ji9NiZxX0Tz 
you: !ZNCAO RESPONSE 51f34b12e2f2a5678a173a97f73fc5dc 

The bot has two things in common with you: a secret, and an emphemeral 32-char challenge it sends everytime it sees you. The response is an md5sum of the secret, ::, and the challenge.

Demo Code
The following is very rough code pruned for shortness, and does not work. It has a lot of detail that took me a while to figure out.

We need an md5 function, and depend on a function (not provided here) to generate random strings of a certain length (generaterandomstring int).

use strict;
use Digest::MD5 qw(md5_hex);

There are two signal handlers for channel joins and notices.

Issuing a challenge
When a nick joins the channel and can be mapped to a shared secret, issue a challenge:

sub message_join {
  my ($server, $channel, $nick, $address) = @_;
  my ($challenge) = generate_random_string(32);
  $server->command("NOTICE $nick !ZNCAO CHALLENGE $challenge");
}

Handling a response
If the bot gets a notice, it could be a response or a challenge.

sub event_notice {
  my ($server, $msg, $nick, $address, $target) = @_;

For a response, calculate the expected response by taking the md5 of the concatenation of shared password, ::, and the challenge sent.

my ($to,$response) = $msg =~ m{^(\S+)\s+:\s*!ZNCAO\s+RESPONSE\s+(.+)$};
my ($expected_response) = md5_hex($password . "::" . $challenge);
if ($response eq $expected_response) {
  # op them
}

Oh, ho! We are challenged
For a challenge, respond using the same formula processing a response and send a notice.

my ($to,$challenge) = $msg =~ m{^(\S+)\s+:\s*!ZNCAO\s+CHALLENGE\s+(.+)$};
my ($response) = md5_hex($password . "::" . $challenge);
$server->command("NOTICE $nick !ZNCAO RESPONSE $response");

Signal Registration
Register the two signals for notices and channel joins.

Irssi::signal_add("event notice", "event_notice");
Irssi::signal_add("message join", "message_join");