From dc524300442e7f4582f895d20c44292b5bee80f8 Mon Sep 17 00:00:00 2001 From: Pragmatic Software Date: Mon, 25 Feb 2013 02:27:24 +0000 Subject: [PATCH] Add SSL support, and other misc updates --- PBot/AntiFlood.pm | 4 ++-- PBot/FactoidCommands.pm | 2 +- PBot/FactoidModuleLauncher.pm | 2 +- PBot/Factoids.pm | 8 ++++---- PBot/IRC/Connection.pm | 37 +++++++++++++++++++++++++++++------ PBot/PBot.pm | 19 ++++++++++++------ PBot/VERSION.pm | 4 ++-- modules/c11std.pl | 2 +- modules/c99std.pl | 2 +- modules/cstd.pl | 2 +- pbot.pl | 18 +++++++++++++++++ 11 files changed, 75 insertions(+), 25 deletions(-) diff --git a/PBot/AntiFlood.pm b/PBot/AntiFlood.pm index 0b62a37b..c5b2bb53 100644 --- a/PBot/AntiFlood.pm +++ b/PBot/AntiFlood.pm @@ -540,8 +540,8 @@ sub check_nickserv_accounts { } foreach my $baninfo (@bans) { - $self->{pbot}->logger->log("anti-flood: [check-bans] $account_mask evaded $baninfo->{banmask} banned in $baninfo->{channel} by $baninfo->{owner}\n"); - $self->{pbot}->conn->privmsg($nick, "You have been banned in $baninfo->{channel} for attempting to evade a ban on $baninfo->{banmask} set by $baninfo->{owner}"); + $self->{pbot}->logger->log("anti-flood: [check-bans] $account_mask may have evaded $baninfo->{banmask} banned in $baninfo->{channel} by $baninfo->{owner}\n"); + #$self->{pbot}->conn->privmsg($nick, "You have been banned in $baninfo->{channel} for attempting to evade a ban on $baninfo->{banmask} set by $baninfo->{owner}"); $account_mask =~ m/[^!]+\!(.*)/; my $banmask = "*!$1"; diff --git a/PBot/FactoidCommands.pm b/PBot/FactoidCommands.pm index cfa5d710..7f14debe 100644 --- a/PBot/FactoidCommands.pm +++ b/PBot/FactoidCommands.pm @@ -693,7 +693,7 @@ sub factfind { chop $text; return "found one factoid submitted for " . ($last_chan eq '.*' ? 'global channel' : $last_chan) . " " . $argtype . ": '$last_trigger' is '" . $factoids->{$last_chan}->{$last_trigger}->{action} . "'"; } else { - return "$i factoids " . $argtype . ": $text" unless $i == 0; + return "found $i factoids " . $argtype . ": $text" unless $i == 0; my $chans = (defined $channel ? ($channel eq '.*' ? 'global channel' : $channel) : 'any channels'); return "No factoids " . $argtype . " submitted for $chans"; diff --git a/PBot/FactoidModuleLauncher.pm b/PBot/FactoidModuleLauncher.pm index 959ac7ad..ed534803 100644 --- a/PBot/FactoidModuleLauncher.pm +++ b/PBot/FactoidModuleLauncher.pm @@ -129,7 +129,7 @@ sub execute_module { Carp::croak("Could not chdir to '$module_dir': $!"); } - print "module arguments: [$arguments]\n"; + # print "module arguments: [$arguments]\n"; if(defined $tonick) { $self->{pbot}->logger->log("($from): $nick!$user\@$host) sent to $tonick\n"); diff --git a/PBot/Factoids.pm b/PBot/Factoids.pm index ead651e6..c916726a 100644 --- a/PBot/Factoids.pm +++ b/PBot/Factoids.pm @@ -207,7 +207,7 @@ sub interpreter { my ($result, $channel); my $pbot = $self->{pbot}; - return undef if not length $keyword; + return undef if not length $keyword or $count > 5; $from = lc $from; @@ -253,13 +253,13 @@ sub interpreter { # if multiple channels have this keyword, then ask user to disambiguate if($found > 1) { - return $ref_from . "Ambiguous keyword '$original_keyword' exists in multiple locations (use 'fact ' to choose one): $chans"; + return $ref_from . "Ambiguous keyword '$original_keyword' exists in multiple channels (use 'fact ' to choose one): $chans"; } # if there's just one other channel that has this keyword, trigger that instance elsif($found == 1) { $pbot->logger->log("Found '$original_keyword' as '$fwd_trig' in [$fwd_chan]\n"); - return $pbot->factoids->interpreter($from, $nick, $user, $host, $count, $fwd_trig, $arguments, $tonick, $fwd_chan); + return $pbot->factoids->interpreter($from, $nick, $user, $host, ++$count, $fwd_trig, $arguments, $tonick, $fwd_chan); } # otherwise keyword hasn't been found, display similiar matches for all channels else { @@ -270,7 +270,7 @@ sub interpreter { # found factfind matches if($matches !~ m/^No factoids/) { - return "No such factoid '$original_keyword'; found $matches"; + return "No such factoid '$original_keyword'; $matches"; } # otherwise find levenshtein closest matches from all channels diff --git a/PBot/IRC/Connection.pm b/PBot/IRC/Connection.pm index 105d8646..f7b50bef 100644 --- a/PBot/IRC/Connection.pm +++ b/PBot/IRC/Connection.pm @@ -50,6 +50,8 @@ my %autoloaded = ( 'ircname' => undef, 'hostname' => undef, 'pacing' => undef, 'ssl' => undef, + 'ssl_ca_path' => undef, + 'ssl_ca_file' => undef, ); # This hash will contain any global default handlers that the user specifies. @@ -77,6 +79,8 @@ sub new { _lastsl => 0, _pacing => 0, # no pacing by default _ssl => 0, # no ssl by default + _ssl_ca_path => undef, + _ssl_ca_file => undef, _format => { 'default' => "[%f:%t] %m <%d>", }, }; @@ -228,6 +232,8 @@ sub connect { $self->username($arg{'Username'}) if exists $arg{'Username'}; $self->pacing($arg{'Pacing'}) if exists $arg{'Pacing'}; $self->ssl($arg{'SSL'}) if exists $arg{'SSL'}; + $self->ssl_ca_path($arg{'SSL_ca_path'}) if exists $arg{'SSL_ca_path'}; + $self->ssl_ca_file($arg{'SSL_ca_file'}) if exists $arg{'SSL_ca_file'}; } # Lots of error-checking claptrap first... @@ -260,12 +266,31 @@ sub connect { if($self->ssl) { require IO::Socket::SSL; - - $self->socket(IO::Socket::SSL->new(PeerAddr => $self->server, - PeerPort => $self->port, - Proto => "tcp", - LocalAddr => $self->hostname, - )); + + if($self->ssl_ca_file) { + $self->socket(IO::Socket::SSL->new(PeerAddr => $self->server, + PeerPort => $self->port, + Proto => "tcp", + LocalAddr => $self->hostname, + SSL_verify_mode => IO::Socket::SSL->SSL_VERIFY_PEER, + SSL_ca_file => $self->ssl_ca_file, + )); + } elsif($self->ssl_ca_path) { + $self->socket(IO::Socket::SSL->new(PeerAddr => $self->server, + PeerPort => $self->port, + Proto => "tcp", + LocalAddr => $self->hostname, + SSL_verify_mode => IO::Socket::SSL->SSL_VERIFY_PEER, + SSL_ca_path => $self->ssl_ca_path, + )); + } else { + $self->socket(IO::Socket::SSL->new(PeerAddr => $self->server, + PeerPort => $self->port, + Proto => "tcp", + LocalAddr => $self->hostname, + )); + } + } else { $self->socket(IO::Socket::INET->new(PeerAddr => $self->server, diff --git a/PBot/PBot.pm b/PBot/PBot.pm index 31f3a327..729ff56b 100644 --- a/PBot/PBot.pm +++ b/PBot/PBot.pm @@ -74,6 +74,10 @@ sub initialize { $self->{module_dir} = delete $conf{module_dir} // "$ENV{HOME}/pbot/modules"; $self->{ircserver} = delete $conf{ircserver} // "irc.freenode.net"; + $self->{port} = delete $conf{port} // 6667; + $self->{SSL} = delete $conf{SSL} // 0; + $self->{SSL_ca_file} = delete $conf{SSL_ca_file} // undef; + $self->{SSL_ca_path} = delete $conf{SSL_ca_path} // undef; $self->{botnick} = delete $conf{botnick} // "pbot3"; $self->{username} = delete $conf{username} // "pbot3"; $self->{ircname} = delete $conf{ircname} // "http://code.google.com/p/pbot2-pl/"; @@ -171,12 +175,15 @@ sub connect { $self->logger->log("Connecting to $server ...\n"); $self->conn($self->irc->newconn( - Nick => $self->{botnick}, - Username => $self->{username}, - Ircname => $self->{ircname}, - Server => $server, - Port => $self->{port})) - or Carp::croak "$0: Can't connect to IRC server.\n"; + Nick => $self->{botnick}, + Username => $self->{username}, + Ircname => $self->{ircname}, + Server => $server, + SSL => $self->{SSL}, + SSL_ca_file => $self->{SSL_ca_file}, + SSL_ca_path => $self->{SSL_ca_path}, + Port => $self->{port})) + or Carp::croak "$0: Can't connect to IRC server.\n"; $self->{connected} = 1; diff --git a/PBot/VERSION.pm b/PBot/VERSION.pm index a1df1328..a49e6fe6 100644 --- a/PBot/VERSION.pm +++ b/PBot/VERSION.pm @@ -13,8 +13,8 @@ use warnings; # These are set automatically by the build/commit script use constant { BUILD_NAME => "PBot", - BUILD_REVISION => 403, - BUILD_DATE => "2013-02-12", + BUILD_REVISION => 404, + BUILD_DATE => "2013-02-24", }; 1; diff --git a/modules/c11std.pl b/modules/c11std.pl index c8ade361..bbc7dfe6 100755 --- a/modules/c11std.pl +++ b/modules/c11std.pl @@ -12,7 +12,7 @@ my $RESULTS_SPECIFIED = 2; my $search = join ' ', @ARGV; if(not length $search) { - print "Usage: c11std [-list] [-n#] [-section
] [search text] -- 'section' must be in the form of X.YpZ where X and Y are section/chapter and, optionally, Z is paragraph. If both 'section' and 'search text' are specified, then the search space will be within the specified section. You may use -n # to skip to the #th match. To list only the section numbers containing 'search text', add -list.\n"; + print "Usage: c11std [-list] [-n#] [-section
] [search text] -- 'section' must be in the form of X.YpZ where X and Y are section/chapter and, optionally, pZ is paragraph. If both 'section' and 'search text' are specified, then the search space will be within the specified section. You may use -n # to skip to the #th match. To list only the section numbers containing 'search text', add -list.\n"; exit 0; } diff --git a/modules/c99std.pl b/modules/c99std.pl index df4dbfc7..1392d67a 100755 --- a/modules/c99std.pl +++ b/modules/c99std.pl @@ -12,7 +12,7 @@ my $RESULTS_SPECIFIED = 2; my $search = join ' ', @ARGV; if(not length $search) { - print "Usage: c99std [-list] [-n#] [-section
] [search text] -- 'section' must be in the form of X.YpZ where X and Y are section/chapter and, optionally, Z is paragraph. If both 'section' and 'search text' are specified, then the search space will be within the specified section. You may use -n # to skip to the #th match. To list only the section numbers containing 'search text', add -list.\n"; + print "Usage: c99std [-list] [-n#] [-section
] [search text] -- 'section' must be in the form of X.YpZ where X and Y are section/chapter and, optionally, pZ is paragraph. If both 'section' and 'search text' are specified, then the search space will be within the specified section. You may use -n # to skip to the #th match. To list only the section numbers containing 'search text', add -list.\n"; exit 0; } diff --git a/modules/cstd.pl b/modules/cstd.pl index 50113a25..e9ba0af0 100755 --- a/modules/cstd.pl +++ b/modules/cstd.pl @@ -12,7 +12,7 @@ my $RESULTS_SPECIFIED = 2; my $search = join ' ', @ARGV; if(not length $search) { - print "Usage: cstd [-list] [-n#] [-section
] [search text] -- 'section' must be in the form of X.YpZ where X and Y are section/chapter and, optionally, Z is paragraph. If both 'section' and 'search text' are specified, then the search space will be within the specified section. You may use -n # to skip to the #th match. To list only the section numbers containing 'search text', add -list.\n"; + print "Usage: cstd [-list] [-n#] [-section
] [search text] -- 'section' must be in the form of X.YpZ where X and Y are section/chapter and, optionally, pZ is paragraph. If both 'section' and 'search text' are specified, then the search space will be within the specified section. You may use -n # to skip to the #th match. To list only the section numbers containing 'search text', add -list.\n"; exit 0; } diff --git a/pbot.pl b/pbot.pl index de8f4601..8ca302cb 100755 --- a/pbot.pl +++ b/pbot.pl @@ -26,6 +26,21 @@ my %config = ( # IRC server address to connect to ircserver => 'irc.freenode.net', + # IRC port + port => '6667', + + # Use SSL? 0 = disabled, 1 = enabled + # Note that you may need to use a specific port for SSL; e.g., freenode uses 6697 or 7000 for SSL + # Uncomment SSL_ca_path or SSL_ca_file below to enable SSL verification (will still work without + # verification, but will be susceptible to man-in-the-middle attacks) + SSL => 0, + + # SSL CA certificates path; e.g., linux: /etc/ssl/certs + # SSL_ca_path => '/etc/ssl/certs', + + # SSL CA file, if SSL_ca_path will not do; e.g., OpenBSD: /etc/ssl/cert.pem + # SSL_ca_file => '/etc/ssl/cert.pem', + # IRC nick (what people see when you talk in channels) # (must be a nick registered with a NickServ account for channel auto-join to work) botnick => 'pbot3', @@ -62,6 +77,9 @@ my %config = ( # You shouldn't need to change anything below this line. # ----------------------------------------------------- + # Maximum messages to remember per nick/hostmask + MAX_NICK_MESSAGES => 256, + # Path to data directory data_dir => "$bothome/data",