forked from miyagawa/cpanminus
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
85 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
name 'verify_checksums'; | ||
description 'Verify CHECKSUMS before unpacking the archive'; | ||
author 'Tatsuhiko Miyagawa'; | ||
|
||
api_version 0.1; | ||
|
||
hook verify_archive => sub { | ||
my $args = shift; | ||
|
||
# Just require and throw errors -- cpanminus will catch them and display it in the build.log | ||
require Module::Signature; | ||
require Digest::SHA; | ||
|
||
# TODO move this logic to cpanminus and set 'source' parameter | ||
my $base = $args->{uri}; | ||
$base =~ s!(authors/id/[A-Z]/[A-Z]{2}/([A-Z]+))/[^/]+\.(?:tar\.gz|tgz|zip)$!$1! | ||
or return; | ||
|
||
my $pause_id = $2; # TODO this can be in the context | ||
my $chk_uri = "$base/CHECKSUMS"; | ||
$args->{app}->chat("Fetching $chk_uri to verifying checksums...\n"); | ||
|
||
my $chk_file = "$pause_id.CHECKSUMS"; | ||
$args->{app}->mirror($chk_uri, $chk_file); | ||
|
||
if (-e $chk_file) { | ||
$args->{app}->chat("Verifying the signature of CHECKSUMS itself...\n"); | ||
|
||
my $rv = eval { | ||
my $v = Module::Signature::_verify($chk_file); | ||
$v == Module::Signature::SIGNATURE_OK(); | ||
}; | ||
if ($rv) { | ||
$args->{app}->chat("Verified OK!\n"); | ||
} else { | ||
$args->{app}->diag("Verifying CHECKSUMS signature failed: $rv\n"); | ||
return $args->{fail}++; | ||
} | ||
|
||
$args->{app}->chat("Verifying the SHA1 for $args->{file}\n"); | ||
|
||
open my $fh, "<$chk_file" or die "$chk_file: $!"; | ||
my $data = join '', <$fh>; | ||
$data =~ s/\015?\012/\n/g; | ||
|
||
require Safe; | ||
my $chksum = Safe->new->reval($data); | ||
|
||
if (!ref $chksum or ref $chksum ne 'HASH') { | ||
$args->{app}->diag("! Checksum file downloaded from $chk_file is broken.\n"); | ||
return $args->{fail}++; | ||
} | ||
|
||
if (my $sha = $chksum->{$args->{file}}{sha256}) { | ||
$args->{app}->chat("Found the checksum for $args->{file}: $sha\n"); | ||
|
||
open my $fh, "<$args->{file}" or die "$args->{file}: $!"; | ||
my $dg = Digest::SHA->new(256); | ||
my($data); | ||
while (read($fh, $data, 4096)) { | ||
$dg->add($data); | ||
} | ||
|
||
my $hex = $dg->hexdigest; | ||
if ($hex eq $sha) { | ||
$args->{app}->chat("Checksum for $args->{file}: Verified!\n"); | ||
} else { | ||
$args->{app}->diag("! Checksum mismatch for $args->{file}: $hex != $sha\n"); | ||
} | ||
} else { | ||
$args->{app}->chat("Checksum for $args->{file} not found in CHECKSUMS.\n"); | ||
} | ||
|
||
} | ||
}; |