use strict; use warnings; package Paranoic; print "Paranoic.pm here..\n"; sub calculate_module_md5{ my $path = shift; open my $file, '<', $path or die "Impossible to open [$path]"; my $ctx = Digest::MD5->new; $ctx->addfile ($file); my $md5 = $ctx->hexdigest; close $file; return $md5; } sub load_md5_from_file{ my %paranoic_INC; open my $file, '<', 'md5-check.txt' or die "Unable to load [md5-check.txt]"; while (<$file>){ chomp $_; next if /^#/; next unless $_; my ($name,$path,$md5) = split /\s+/,$_; $paranoic_INC{ $name } = { path => $path, expected_md5 => $md5, }; } return \%paranoic_INC; } sub traverse_INC{ my $filename = shift; my @original_INC = @_; } BEGIN { my @original_INC = @INC; use Digest::MD5 ; use File::Spec; #print "BEFORE: ",map {"$_ $INC{$_}\n"} keys %INC; print "BEFORE any hook I will check md5 of already loaded module:\n"; my $paranoic_inc = load_md5_from_file(); foreach my $module ( keys %INC ){ # SKIP itself while developping it # next if $module eq 'Paranoic.pm'; #test #if ($module eq 'Exporter.pm'){$$paranoic_inc{$module}{expected_md5}.='XXXXX'} my $md5 = calculate_module_md5( $INC{$module} ); # NOT FOUND if (! exists $$paranoic_inc{$module} ){ # this is a die print "Cannot find a stored md5 for [$module]"; print "\n-->DEBUG: $module\t$INC{$module}\t$md5\n"; } # WHITELIST elsif ( 'ALLOW' eq $$paranoic_inc{$module}{expected_md5} ){ print " WHITELIST for $module at $$paranoic_inc{$module}{path} [$md5]\n"; } # BLACKLIST elsif ( 'DENY' eq $$paranoic_inc{$module}{expected_md5} ){ # this is a die print " DENY for $module at $$paranoic_inc{$module}{path} [$md5]\n"; } # EXPECTED MD5 elsif ( $md5 eq $$paranoic_inc{$module}{expected_md5} ){ print " OK $module at $$paranoic_inc{$module}{path} has the expected md5: ". "$$paranoic_inc{$module}{expected_md5}\n"; } # WRONG MD5 elsif ( $md5 ne $$paranoic_inc{$module}{expected_md5} ){ # this is a die.. print "ERROR: $module at $$paranoic_inc{$module}{path} has [$md5] ". "insetead of [$$paranoic_inc{$module}{expected_md5}]"; } # UNKNOWN RESULT else{ die "UNKNOWN error for $module at $$paranoic_inc{$module}{path} with md5 [$md5]" } } print "\nAFTER I will use some hook to check md5 of modules loaded by the calling program\n"; if ( $^V ge '5.38.0'){ print "====> Perl $^V using \$^HOOK\n"; ${^HOOK}{require__before} = sub { my $filename = shift; if ( exists $INC{$filename} ){ print " SKIP [$filename] already processed\n"; return; } print "Paranoically considering [$filename]\n"; }; } else{ print "====> Perl $^V using \@INC\n"; unshift @INC, sub { my ($self,$filename) = @_; print "Paranoically considering [$filename]\n"; }; } } 1;