File Coverage

blib/lib/POE/Component/IRC/Plugin/Blowfish.pm
Criterion Covered Total %
statement 51 139 36.6
branch 1 16 6.2
condition n/a
subroutine 14 26 53.8
pod 3 8 37.5
total 69 189 36.5


line stmt bran cond sub pod time code
1             package POE::Component::IRC::Plugin::Blowfish;
2              
3 1     1   360218 use strict;
  1         2  
  1         35  
4 1     1   5 use warnings;
  1         3  
  1         27  
5 1     1   5 use POE;
  1         6  
  1         7  
6 1     1   409 use POE::Component::IRC::Plugin qw( :ALL );
  1         2  
  1         153  
7 1     1   903 use Crypt::Blowfish_PP;
  1         1848  
  1         29  
8 1     1   8 use Carp qw/croak/;
  1         2  
  1         55  
9 1     1   5 use vars qw($VERSION);
  1         2  
  1         44  
10              
11             $VERSION = '0.01';
12              
13 1         63 use constant B64 =>
14 1     1   5 './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  1         3  
15              
16 1     1   4 use constant states => qw/set_blowfish_key del_blowfish_key/;
  1         1  
  1         1848  
17              
18             sub new {
19 1     1 1 6598 my $package = shift;
20 1 50       6 croak "Plugin requires an even number of parameters" if @_ % 2;
21              
22 1         3 my $self = { targets => {@_} };
23 1         4 bless $self, $package;
24              
25 1         2 foreach my $chan ( keys %{ $self->{targets} } ) {
  1         6  
26 0         0 $self->_set_key( $chan, $self->{targets}->{$chan} );
27             }
28              
29 1         4 return $self;
30             }
31              
32             sub PCI_register {
33 1     1 0 420 my ( $self, $irc ) = splice @_, 0, 2;
34              
35 1         5 $irc->plugin_register( $self, 'SERVER', qw(public 001) );
36 1         30 $irc->plugin_register( $self, 'USER', qw(privmsg) );
37              
38 2         8 $self->{session_id} =
39             POE::Session->create( object_states =>
40 1         23 [ $self => [ qw/_shutdown _start/, map { "_$_" } states ], ], )->ID;
41              
42 1         126 $poe_kernel->state( $_ => $self ) for states;
43              
44 1         86 return 1;
45             }
46              
47             sub PCI_unregister {
48 1     1 0 1955 my ( $self, $irc ) = splice @_, 0, 2;
49              
50 1         8 $poe_kernel->state($_) for states;
51 1         43 $poe_kernel->call( $self->{session_id} => '_shutdown' );
52 1         57 return 1;
53             }
54              
55             sub _start {
56 1     1   133 my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
57 1         15 $self->{session_id} = $_[SESSION]->ID();
58 1         8 $kernel->refcount_increment( $self->{session_id}, __PACKAGE__ );
59             }
60              
61             sub _shutdown {
62 1     1   58 my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
63 1         5 $kernel->alarm_remove_all();
64 1         56 $kernel->refcount_decrement( $self->{session_id}, __PACKAGE__ );
65             }
66              
67             sub set_blowfish_key {
68 0     0 1   my ( $kernel, $self, $sender ) = @_[ KERNEL, OBJECT, SENDER ];
69 0           $kernel->post( $self->{session_id}, '_set_blowfish_key', $sender,
70             @_[ ARG0 .. $#_ ] );
71             }
72              
73             sub del_blowfish_key {
74 0     0 1   my ( $kernel, $self, $sender ) = @_[ KERNEL, OBJECT, SENDER ];
75 0           $kernel->post( $self->{session_id}, '_del_blowfish_key', $sender,
76             @_[ ARG0 .. $#_ ] );
77             }
78              
79             sub _set_blowfish_key {
80 0     0     my ( $kernel, $self, $sender, $chan, $key ) =
81             @_[ KERNEL, OBJECT, ARG0 .. ARG2 ];
82 0           my $old_key;
83 0 0         $old_key = $self->{targets}->{$chan}->[1]
84             if defined $self->{targets}->{$chan};
85 0           $self->_set_key( $chan, $key );
86             }
87              
88             sub _del_blowfish_key {
89 0     0     my ( $kernel, $self, $sender, $chan ) = @_[ KERNEL, OBJECT, ARG0, ARG1 ];
90 0 0         delete $self->{targets}->{$chan} if defined $self->{targets}->{$chan};
91             }
92              
93             sub S_001 {
94 0     0 0   my ( $self, $irc ) = splice @_, 0, 2;
95              
96             # get this plugin to the pole position
97 0           $irc->pipeline->bump_up($self) while $irc->pipeline->get_index($self) > 0;
98              
99 0           return PCI_EAT_NONE;
100             }
101              
102             sub U_privmsg {
103 0     0 0   my ( $self, $irc ) = splice @_, 0, 2;
104              
105 0           my $line = ${ $_[0] };
  0            
106 0           my ( $target, $msg ) = $line =~ /PRIVMSG (.*?) :(.*?)$/;
107              
108 0 0         return PCI_EAT_NONE unless defined $self->{targets}->{$target};
109              
110 0           $msg = sprintf '+OK %s',
111             $self->_encrypt( $msg, $self->{targets}->{$target}->[0] );
112              
113 0           ${ $_[0] } = sprintf 'PRIVMSG %s :%s', $target, $msg;
  0            
114              
115 0           return PCI_EAT_NONE;
116             }
117              
118             sub S_public {
119 0     0 0   my ( $self, $irc ) = splice @_, 0, 2;
120              
121 0           my ($nick) = ( split /!/, ${ $_[0] } )[0];
  0            
122 0           my ($target) = ${ $_[1] }->[0];
  0            
123 0           my ($msg) = ${ $_[2] };
  0            
124              
125 0 0         if ( defined $self->{targets}->{$target} ) {
126 0 0         if ($msg =~ s/^\+OK //) {
127 0           $msg = $self->_decrypt( $msg, $self->{targets}->{$target}->[0] );
128 0           $msg =~ s/\0//g;
129 0           ${ $_[2] } = $msg;
  0            
130             }
131             }
132              
133 0           return PCI_EAT_NONE;
134             }
135              
136             sub _encrypt {
137 0     0     my ( $self, $text, $key ) = @_;
138              
139 0           $text =~ s/(.{8})/$1\n/g;
140 0           my $result = '';
141 0           my $cipher = new Crypt::Blowfish_PP $key;
142 0           foreach ( split /\n/, $text ) {
143 0           $result .= $self->_inflate( $cipher->encrypt($_) );
144             }
145              
146 0           return $result;
147             }
148              
149             sub _decrypt {
150 0     0     my ( $self, $text, $key ) = @_;
151              
152 0           $text =~ s/(.{12})/$1\n/g;
153 0           my $result = '';
154 0           my $cipher = new Crypt::Blowfish_PP $key;
155 0           foreach ( split /\n/, $text ) {
156 0           $result .= $cipher->decrypt( $self->_deflate($_) );
157             }
158              
159 0           return $result;
160             }
161              
162             sub _set_key {
163 0     0     my ( $self, $chan, $key ) = @_;
164              
165 0           $self->{targets}->{$chan} = [ $key, $key ];
166              
167 0           my $l = length($key);
168              
169 0 0         if ( $l < 8 ) {
170 0           my $longkey = '';
171 0           my $i = 8 / $l;
172 0 0         $i = $1 + 1 if $i =~ /(\d+)\.\d+/;
173 0           while ( $i > 0 ) {
174 0           $longkey .= $key;
175 0           $i--;
176             }
177 0           $self->{targets}->{$chan} = [ $longkey, $key ];
178             }
179             }
180              
181             sub _inflate {
182 0     0     my ( $self, $text ) = @_;
183 0           my $result = '';
184 0           my $k = -1;
185              
186 0           while ( $k < ( length($text) - 1 ) ) {
187 0           my ( $l, $r ) = ( 0, 0 );
188 0           for ( $l, $r ) {
189 0           foreach my $i ( 24, 16, 8 ) {
190 0           $_ += ord( substr( $text, ++$k, 1 ) ) << $i;
191             }
192 0           $_ += ord( substr( $text, ++$k, 1 ) );
193             }
194 0           for ( $r, $l ) {
195 0           foreach my $i ( 0 .. 5 ) {
196 0           $result .= substr( B64, $_ & 0x3F, 1 );
197 0           $_ = $_ >> 6;
198             }
199             }
200             }
201 0           return $result;
202             }
203              
204             sub _deflate {
205 0     0     my ( $self, $text ) = @_;
206 0           my $result = '';
207 0           my $k = -1;
208              
209 0           while ( $k < ( length($text) - 1 ) ) {
210 0           my ( $l, $r ) = ( 0, 0 );
211 0           for ( $r, $l ) {
212 0           foreach my $i ( 0 .. 5 ) {
213 0           $_ |= index( B64, substr( $text, ++$k, 1 ) ) << ( $i * 6 );
214             }
215             }
216 0           for ( $l, $r ) {
217 0           foreach my $i ( 0 .. 3 ) {
218 0           $result .=
219             chr( ( $_ & ( 0xFF << ( ( 3 - $i ) * 8 ) ) )
220             >> ( ( 3 - $i ) * 8 ) );
221             }
222             }
223             }
224              
225 0           return $result;
226             }
227              
228             1;
229             __END__