package My::PGPFindKey; ############################################### # Author: retoh@cuthere-infocopter.com # Created: 08SEP2003 # my $VERSION = '0.81.01'; ############################################### use strict; my $package = __PACKAGE__; use LWP::UserAgent; # GLOBAL VARIABLES my %Var = (); my $contentType = ""; my @hrefs = (); $| = 1; #----- FORWARD DECLARATIONS & PROTOTYPING sub Debug($); sub new { my $type = shift; my %params = @_; my $self = {}; $self->{'proto' } = $params{'proto' } || 'http://'; $self->{'keyserver' } = $params{'keyserver' } || 'pgp.mit.edu:11371'; $self->{'path' } = $params{'path' } || '/pks/lookup'; $self->{'command' } = $params{'command' } || '?op=index&search='; $self->{'localdb' } = $params{'localdb' } || 'PGPFindKey_local.txt'; $self->{'maxresults'} = $params{'maxresults'} || 100; $self->{'debug'} = $Var{'debug'} = $params{'debug'}; $Var{'server_prefix'} = $self->{'proto'} . $self->{'keyserver'} ; Debug "$package V$VERSION" if $self->{'debug'}; bless $self, $type; } sub find { my $self = shift; my %Params = @_; my %result = (); $result{'rc'} = $result{'count'} = 0; $result{'rmsg'} = 'Ok'; Debug "[find] Key Server: " . $self->{'keyserver'}; Debug "$_ = $Params{$_}" foreach keys %Params; my @stopqueries = qw(your spam test); foreach (@stopqueries) { if ($Params{'query'} =~ /$_/i) { $result{'rc'} = -2; $result{'rmsg'} = 'CONTAINS STOP WORD(S)!'; return \%result; } Debug "$_"; } my $uri = $self->{'proto'} . $self->{'keyserver'} . $self->{'path'} . $self->{'command'}; my $ua = LWP::UserAgent->new(agent => "infocopter.com/pgp-keyserver-api.htm V$VERSION"); my $r = HTTP::Request->new('GET', "$uri$Params{'query'}"); $Var{'res'} = $ua->request($r); if ($Var{'res'}->is_success) { my $result = &parse($Var{'res'}->content()); open(CACHE, '<' . $self->{'localdb'}); my @local_lines = ; close CACHE; chomp @local_lines; # Debug "RESULT"; my $i = 0; foreach (@$result) { my ($uri, $desc, $email) = split /\t/; $desc =~ s/ *$//; # trim trailing spaces my $foo = my $time = my $status = my $revoked = ''; foreach (@local_lines) { if ($_ =~ /^$email/i) { ($foo, $time, $status) = split /\|/; $desc .= " ($status)"; $revoked = 1 if $status eq 'REVOKED'; last; } } next if $revoked; Debug $desc; Debug $email; Debug "-------------------------------------------"; $r = HTTP::Request->new('GET', $uri); my $res = $ua->request($r); my $public_key_ref = &extract_public_key($res->content()); my $public_key = ''; foreach (@$public_key_ref) { Debug $_; $public_key .= "$_\n"; } my %record_response = (); $record_response{'comment' } = $desc; $record_response{'publickey'} = $public_key; $email .= "\t[" . ++$i . ']' if defined $result{$email}; $result{$email} = \%record_response; if (++$result{'count'} > $self->{'maxresults'} - 1) { $result{'rc'} = 99; last; } } } else { Debug $uri; $result{'rc'} = -1; } \%result; } sub parse ($) { my $response = $_[0]; my @lines = split /\n/, $response; my $i = 0; for ($i = 0; $i < $#lines + 1; $i++) { last if $lines[$i] =~ /\
/;
	}

	my @result = ();

	for ($i = $i + 2; $i < $#lines + 1; $i++) {
		last if $lines[$i] =~ /\<\/pre>/;

		next if ($lines[$i] !~ /pub/ or $lines[$i] !~ /\@/);
		my @elems = split /\"/, $lines[$i];
		$elems[1] = $Var{'server_prefix'} . $elems[1] ;
		$elems[2] =~ s/.+\<\/a> *(.+) *\<.+/$1/;
		
		$elems[4] =~ s/.*\>(.+\@.+)<\/a\>\>.*/$1/;

		# uri, description, email
		push(@result, "$elems[1]\t$elems[2]\t$elems[4]");
	}

	\@result;
}

sub extract_public_key ($) {
	my @lines = split /\n/, $_[0];

	my $i = 0;
	for ($i = 0; $i < $#lines + 1; $i++) {
		last if $lines[$i] =~ /\
/;
	}

	my @result = ();

	for ($i = $i + 1; $i < $#lines + 1; $i++) {
		last if $lines[$i] =~ /\<\/pre>/;
		push(@result, $lines[$i]);
	}

	\@result;
}

sub Debug ($)  {
	return unless $Var{'debug'};
	print "[ $package ] $_[0]
\n"; } 1; __END__ # USAGE: use My::PGPFindKey; ################################################## # FETCH A SPECIFIC PUBLIC KEY BY E-MAIL ADDRESS: ################################################## my $certserver = new My::PGPFindKey (); my $email = 'retoh@infocopter.ch'; my $result = $certserver->find( query => $email ); if ($result->{'rc'}) { print "ERR"; } print $result->{$email}->{'comment'}, "\n"; print $result->{$email}->{'publickey'}, "\n\n"; ################################################## # PROCESS A LIST OF RESULTS ################################################## my $certserver = new My::PGPFindKey ( keyserver => 'pgp.mit.edu:11371' , # optional maxresults => 10 , debug => 0 ); my $result = $certserver->find( query => $ARGV[0] ); if ($result->{'rc'}) { print "ERR"; } delete $result->{'rc'}; delete $result->{'count'}; foreach my $email (keys %$result) { print "$email\n"; print $result->{$email}->{'comment'}, "\n"; print $result->{$email}->{'publickey'}, "\n\n"; }