#!/usr/bin/env perl # by virii - C3L use strict; use warnings; use diagnostics; use utf8; use YAML::Tiny; use XML::LibXML; use MIME::Base64; use Net::EasyTCP; use AnyEvent::XMLRPC; use experimental 'smartmatch'; ################################################################################################## my ($YAMLoutput, $YAMLbase64, $YAMLconfig); my ($member, $memberstatus, $membercounter, $username); my ($voting, $birthday, $address, $votingright, $votingrights); my ($regularmember, $studentmember, $supportmember, $starvingmember, $bifröstconfig); my ($serv, $sharedsecret, $XMLparser, $XMLfile, $XMLquery, $XMLnode, $TCPclient, $TCPreply); my ($chaosid, $lastname, $forename, $email, $status, $date, $paid, $userbox, $keyowner, $comment); my (@members, @usernames, %usercontacts); my @sharedsecrets = ('secret', 'password'); ################################################################################################## ################################################################################################## $YAMLconfig = YAML::Tiny->read( '/etc/bifröst/client-config.yml' ) || die "[-] File not found or not a valid YAML"; $bifröstconfig = $YAMLconfig->[0]; ################################################################################################## $serv = AnyEvent::XMLRPC->new( port => 9090, uri => "/RPC2", ssl => { cert_file => "/etc/midgard/cert.pem", key_file => "/etc/midgard/key.pem" }, methods => { 'CHAOSID' => \&CHAOSID, 'COUNTER' => \&COUNTER, 'MEMBERINFO' => \&MEMBERINFO, 'VOTINGRIGHT' => \&VOTINGRIGHT }, ); sub CHAOSID { ($sharedsecret, $chaosid) = ("none", 0); ($sharedsecret, $chaosid) = @_; return "FUCK OFF" unless ($sharedsecret ~~ @sharedsecrets); return "NO CHAOS ID" unless (length $chaosid == 36); _OPEN_DATABASE(); $username = 0; $XMLquery = "/memberdatebank/memberen/member[id/text() = '$chaosid']"; foreach $XMLnode ($XMLfile->findnodes($XMLquery)) { $username = $XMLnode->findnodes('./nick'); } return "NO SUCH USER" unless $username; $YAMLoutput = YAML::Tiny->new( { ChaosID => "$chaosid", Username => "$username" } ); chomp ($YAMLbase64 = encode_base64 $YAMLoutput->write_string); return $YAMLbase64; } sub MEMBERINFO { ($sharedsecret, $username) = ("none", 0); ($sharedsecret, $username) = @_; return "FUCK OFF" unless ($sharedsecret ~~ @sharedsecrets); return "NO USER" unless $username; _OPEN_DATABASE(); ($chaosid, $lastname, $forename, $email, $status, $date, $paid, $userbox, $keyowner, $comment) = 0; $XMLquery = "/memberdatebank/memberen/member[nick/text() = '$username']"; foreach $XMLnode ($XMLfile->findnodes($XMLquery)) { $chaosid = $XMLnode->findnodes('./id'); $forename = $XMLnode->findnodes('./numm'); $lastname = $XMLnode->findnodes('./nonumm'); $birthday = $XMLnode->findnodes('./gebuertsdag'); $address = $XMLnode->findnodes('./adress'); $email = $XMLnode->findnodes('./email'); $status = $XMLnode->findnodes('./status'); $voting = int $XMLnode->findnodes('./stemmrecht'); $date = $XMLnode->findnodes('./datum'); $paid = int $XMLnode->findnodes('./bezuelt'); $userbox = int $XMLnode->findnodes('./kescht'); $keyowner = int $XMLnode->findnodes('./badge'); $comment = $XMLnode->findnodes('./kommentar'); } return "NO SUCH USER" unless $chaosid; $YAMLoutput = YAML::Tiny->new( { ChaosID => "$chaosid", Names => { 'Forename' => "$forename", 'Lastname' => "$lastname", 'Username' => "$username" }, Email => "$email", Status => "$status", Voters => "$voting", More => { 'Address' => "$address", 'Birthday' => "$birthday", 'Storagebox' => "$userbox", 'Payment' => "$date", 'Paid' => "$paid", 'Keyowner' => "$keyowner", 'Comment' => "$comment" } } ); chomp ($YAMLbase64 = encode_base64 $YAMLoutput->write_string); return $YAMLbase64; } sub COUNTER { $sharedsecret = shift||"none"; return "FUCK OFF" unless ($sharedsecret ~~ @sharedsecrets); _OPEN_DATABASE(); ($regularmember, $supportmember, $studentmember, $starvingmember, $votingrights) = 0; foreach $member (@members) { $memberstatus = $member->findnodes('./status'); $votingright = $member->findnodes('./stemmrecht'); $votingrights++ if int $votingright; $regularmember++ if ($memberstatus =~ /^Regular$/i); $studentmember++ if ($memberstatus =~ /^Student$/i); $supportmember++ if ($memberstatus =~ /^Supporter/i); $starvingmember++ if ($memberstatus =~ /^Starving$/i); } $membercounter = scalar @members; $YAMLoutput = YAML::Tiny->new( { Counter => $membercounter, Voters => $votingrights, Regular => $regularmember, Student => $studentmember, Supporter => $supportmember, Starving => $starvingmember } ); chomp ($YAMLbase64 = encode_base64 $YAMLoutput->write_string); return $YAMLbase64; } sub VOTINGRIGHT { $sharedsecret = shift||"none"; return "FUCK OFF" unless ($sharedsecret ~~ @sharedsecrets); _OPEN_DATABASE(); $votingrights = 0; $XMLquery = "/memberdatebank/memberen/member[stemmrecht/text() = '1']"; foreach $XMLnode ($XMLfile->findnodes($XMLquery)) { ($username, $email) = ( $XMLnode->findnodes('./nick') . '', $XMLnode->findnodes('./email') . ''); # Don't know why but I have to add "nothing" to the string to make YAML::Tiny work with XML::LibXML push @usernames, $username; $usercontacts{$username} = $email; $votingrights++; } $YAMLoutput = YAML::Tiny->new( { Voters => "$votingrights", Usernames => [@usernames], Contact => { %usercontacts } } ); chomp ($YAMLbase64 = encode_base64 $YAMLoutput->write_string); undef @usernames; return $YAMLbase64; } ## # Internal subroutine ## sub _OPEN_DATABASE { $TCPclient = new Net::EasyTCP( mode => "client", host => $bifröstconfig->{host}, port => $bifröstconfig->{port}, password => $bifröstconfig->{pass} ) || die "[-] Cannot connect!\n"; $TCPclient->send("SERVE") || die "[-] Error sending: $@\n"; $TCPreply = $TCPclient->receive() || die "[-] Error receiving: $@\n"; $XMLparser = XML::LibXML->new(); $XMLfile = $XMLparser->parse_string($TCPreply); @members = $XMLfile->findnodes('/memberdatebank/memberen/member'); } $serv->run;