diff --git a/MANIFEST b/MANIFEST index 1043eea..d00b6c9 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,31 +1,24 @@ +.mailmap ANDK2020.pub AUDREYT2018.pub AUTHORS Changes -inc/Module/Install.pm -inc/Module/Install/Base.pm -inc/Module/Install/Can.pm -inc/Module/Install/External.pm -inc/Module/Install/Fetch.pm -inc/Module/Install/Makefile.pm -inc/Module/Install/Metadata.pm -inc/Module/Install/Scripts.pm -inc/Module/Install/Win32.pm -inc/Module/Install/WriteAll.pm +cpanfile +dist.ini lib/Module/Signature.pm +maint/Makefile_header.PL Makefile.PL MANIFEST This list of files MANIFEST.SKIP -META.yml NIKLASHOLM2018.pub PAUSE2022.pub -TIMLEGGE2024.pub README script/cpansign -SIGNATURE +SECURITY.md t/0-signature.t t/1-basic.t t/2-cygwin.t t/3-verify.t t/wrap.pl t/wrapped-tests.bin +TIMLEGGE2024.pub diff --git a/Makefile.PL b/Makefile.PL index a871f9d..a718480 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1,82 +1,264 @@ +# Dist::Zilla::Plugin::MakeMaker::Awesome 0.49. +# Don't edit it but the dist.ini and plugins used to construct it. + use strict; use warnings; -use 5.010; - use ExtUtils::MakeMaker; +use FindBin '$Bin'; +use lib $Bin; + +$|++; +my %requires; +my %args; +$args{LICENSE} = 'unrestricted'; +# clean generated test files +$args{clean} = {FILES => "t/test-dat*"}; + +# On Win32 (excluding cygwin) we know that IO::Socket::INET, +# which is needed for keyserver stuff, doesn't work. In fact +# it potentially hangs forever. So bail out with a N/A on +# Win32. +if ( $^O eq 'MSWin32' and 0 ) { + print "Keyserver behaviour is dangerous unreliable on Win32\n"; + print "Not installing on this platform.\n"; + exit(255); +} else { + $requires{'IO::Socket::INET'} = 0; +} + +# We will need something to handle SHA1/256 +unless ( + can_use('Digest::SHA') or + can_use('Digest::SHA::PurePerl') or + (can_use('Digest::SHA1') and can_use('Digest::SHA256')) +) { + # Nothing installed, we need to install a digest module + if ( can_cc() ) { + $requires{'Digest::SHA'} = 0; + } else { + $requires{'Digest::SHA::PurePerl'} = 0; + } +} + +# Is openpgp currently installed +if ( can_use ('Crypt::OpenPGP') ) { + # Crypt::OpenPGP installed/available, continue on... +} elsif ( my $gpg = locate_gpg() ) { + # We SHOULD have gpg, double-check formally + requires_external_bin ($gpg); +} elsif ( can_cc() and $ENV{AUTOMATED_TESTING} ) { + # Dive headlong into a full Crypt::OpenPGP install. + $requires{'Crypt::OpenPGP'} = 0; +} else { + # Ask the user what to do + ask_user(); +} + +unless ( can_run('diff') ) { + # We know Text::Diff fails on Cygwin (for now) + if ( $^O ne 'Cygwin' ) { + $requires{'Algorithm::Diff'} = 0; + $requires{'Text::Diff'} = 0; + } + } + +##################################################################### +# Support Functions + +sub locate_gpg { + print "Looking for GNU Privacy Guard (gpg), a cryptographic signature tool...\n"; + + my ($gpg, $gpg_path); + for my $gpg_bin ('gpg', 'gpg2', 'gnupg', 'gnupg2') { + $gpg_path = can_run($gpg_bin); + next unless $gpg_path; + next unless `$gpg_bin --version` =~ /GnuPG/; + next unless defined `$gpg_bin --list-public-keys`; + + $gpg = $gpg_bin; + last; + } + unless ( $gpg ) { + print "gpg not found.\n"; + return; + } + + print "GnuPG found ($gpg_path).\n"; + + return 1 if grep { /^--installdeps/} @ARGV; + + if ( prompt("Import PAUSE and author keys to GnuPG?", 'y' ) =~ /^y/i) { + print 'Importing... '; + system $gpg, '--quiet', '--import', qw[ AUDREYT2018.pub ANDK2020.pub PAUSE2022.pub NIKLASHOLM2018.pub TIMLEGGE2024.pub ]; + print "done.\n"; + } + + return $gpg; +} + +sub ask_user { + + # Defined the prompt messages + my $message1 = <<'END_MESSAGE'; + +Could not auto-detect a signature utility on your system. + +What do you want me to do? + +1) Let you install GnuPG manually while I'm waiting for your answer; + it is available at http://www.gnupg.org/download/ or may be available + from your platforms packaging system (for Open Source platforms). + +END_MESSAGE + + my $message2 = <<'END_MESSAGE'; + +2) Automatically install Crypt::OpenPGP and the 20 modules it requires + from CPAN, which will give the same functionality as GnuPG. + +END_MESSAGE + + # Present the options + print $message1; + + my $option3 = 2; + if ( can_cc() ) { + $option3 = 3; + print $message2; + } + + print <<"END_MESSAGE"; + +$option3) Forget this cryptographic signature stuff for now. + +END_MESSAGE + + my $choice; + foreach ( 1 .. 3 ) { + $choice = prompt("Your choice:", 3) || 3; + last if $choice =~ /^[123]$/; + print "Sorry, I cannot understand '$choice'.\n" + } + + if ( $choice == 1 ) { + # They claim to have installed gpg + requires_external_bin ('gpg'); + } elsif ( $choice == 2 and $option3 == 3 ) { + # They want to install Crypt::OpenPGP + $requires{'Crypt::OpenPGP'} = 0; + } else { + # Forget about it... + print "Module::Signature is not wanted on this host.\n"; + exit(0); + } +} + +# check if we can load some module +### Upgrade this to not have to load the module if possible +sub can_use { + my ($mod, $ver) = @_; + $mod =~ s{::|\\}{/}g; + $mod .= '.pm' unless $mod =~ /\.pm$/i; + my $pkg = $mod; + $pkg =~ s{/}{::}g; + $pkg =~ s{\.pm$}{}i; + local $@; + eval { require $mod; $pkg->VERSION($ver || 0); 1 }; +} + +# Check if we can run some command +sub can_run { + my ($cmd) = @_; + my $_cmd = $cmd; + return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); + for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { + next if $dir eq ''; + require File::Spec; + my $abs = File::Spec->catfile($dir, $cmd); + return $abs if (-x $abs or $abs = MM->maybe_command($abs)); + } + return; +} +# Can we locate a (the) C compiler +sub can_cc { + if ($^O eq 'VMS') { + require ExtUtils::CBuilder; + my $builder = ExtUtils::CBuilder->new( + quiet => 1, + ); + return $builder->have_compiler; + } + my @chunks = split(/ /, $Config::Config{cc}) or return; + # $Config{cc} may contain args; try to find out the program part + while (@chunks) { + return can_run("@chunks") || (pop(@chunks), next); + } + return; +} + +sub requires_external_bin { + my ($bin, $version) = @_; + if ( $version ) { + die "requires_external_bin does not support versions yet"; + } + # Load the package containing can_run early, + # to avoid breaking the message below. + # Locate the bin + print "Locating bin:$bin..."; + my $found_bin = can_run( $bin ); + if ( $found_bin ) { + print " found at $found_bin.\n"; + } else { + print " missing.\n"; + print "Unresolvable missing external dependency.\n"; + print "Please install '$bin' seperately and try again.\n"; + print STDERR "NA: Unable to build distribution on this platform.\n"; + exit(0); + } + # Once we have some way to specify external deps, do it here. + # In the mean time, continue as normal. + 1; +} + my %WriteMakefileArgs = ( "ABSTRACT" => "Module signature file manipulation", "AUTHOR" => "Audrey Tang ", + "BUILD_REQUIRES" => { + "ExtUtils::MakeMaker" => "6.36", + "IPC::Run" => 0, + "Test::More" => 0 + }, "CONFIGURE_REQUIRES" => { - "ExtUtils::MakeMaker" => 0 + "ExtUtils::MakeMaker" => "6.36" }, "DISTNAME" => "Module-Signature", "LICENSE" => "perl", - "MIN_PERL_VERSION" => "5.010", "NAME" => "Module::Signature", "PREREQ_PM" => { - "Crypt::OpenPGP" => 0, - "Crypt::OpenPGP::KeyServer" => 0, - "Exporter" => 0, - "ExtUtils::Manifest" => 0, - "File::Spec" => 0, - "File::Temp" => 0, - "IO::Socket::INET" => 0, - "Text::Diff" => 0, - "constant" => 0, - "strict" => 0, - "vars" => 0, - "version" => 0, - "warnings" => 0 - }, - "TEST_REQUIRES" => { - "Data::Dumper" => 0, - "File::Basename" => 0, - "File::Path" => 0, - "FindBin" => 0, - "Getopt::Long" => 0, - "IPC::Run" => 0, - "Pod::Usage" => 0, - "Socket" => 0, - "Test::More" => 0, - "lib" => 0 + "File::Temp" => 0 }, - "VERSION" => "0.90", + "VERSION" => "0.91", "test" => { "TESTS" => "t/*.t" } ); +%WriteMakefileArgs = ( + %WriteMakefileArgs, + %args, + PREREQ_PM => {%{$WriteMakefileArgs{PREREQ_PM}}, %requires}, +); my %FallbackPrereqs = ( - "Crypt::OpenPGP" => 0, - "Crypt::OpenPGP::KeyServer" => 0, - "Data::Dumper" => 0, - "Exporter" => 0, - "ExtUtils::Manifest" => 0, - "File::Basename" => 0, - "File::Path" => 0, - "File::Spec" => 0, + "ExtUtils::MakeMaker" => "6.36", "File::Temp" => 0, - "FindBin" => 0, - "Getopt::Long" => 0, - "IO::Socket::INET" => 0, "IPC::Run" => 0, - "Pod::Usage" => 0, - "Socket" => 0, - "Test::More" => 0, - "Text::Diff" => 0, - "constant" => 0, - "lib" => 0, - "strict" => 0, - "vars" => 0, - "version" => 0, - "warnings" => 0 + "Test::More" => 0 ); - -unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { +unless ( eval { ExtUtils::MakeMaker->VERSION('6.63_03') } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; diff --git a/README b/README index 77bdd86..bd8c8ed 100644 --- a/README +++ b/README @@ -1,22 +1,21 @@ NAME - Module::Signature - Module signature file manipulation -VERSION - version 0.90 + Module::Signature - Module signature file manipulation SYNOPSIS + As a shell command: % cpansign # verify an existing SIGNATURE, or # make a new one if none exists - + % cpansign sign # make signature; overwrites existing one % cpansign -s # same thing - + % cpansign verify # verify a signature % cpansign -v # same thing % cpansign -v --skip # ignore files in MANIFEST.SKIP - + % cpansign help # display this documentation % cpansign -h # same thing @@ -25,25 +24,25 @@ SYNOPSIS use Module::Signature qw(sign verify SIGNATURE_OK); sign(); sign(overwrite => 1); # overwrites without asking - + # see the CONSTANTS section below (verify() == SIGNATURE_OK) or die "failed!"; DESCRIPTION + Module::Signature adds cryptographic authentications to CPAN distributions, via the special SIGNATURE file. If you are a module user, all you have to do is to remember to run - "cpansign -v" (or just "cpansign") before issuing "perl Makefile.PL" or - "perl Build.PL"; that will ensure the distribution has not been tampered - with. + cpansign -v (or just cpansign) before issuing perl Makefile.PL or perl + Build.PL; that will ensure the distribution has not been tampered with. Module authors can easily add the SIGNATURE file to the distribution - tarball; see "NOTES" below for how to do it as part of "make dist". + tarball; see "NOTES" below for how to do it as part of make dist. - If you *really* want to sign a distribution manually, simply add - "SIGNATURE" to MANIFEST, then type "cpansign -s" immediately before - "make dist". Be sure to delete the SIGNATURE file afterwards. + If you really want to sign a distribution manually, simply add + SIGNATURE to MANIFEST, then type cpansign -s immediately before make + dist. Be sure to delete the SIGNATURE file afterwards. Please also see "NOTES" about MANIFEST.SKIP issues, especially if you are using Module::Build or writing your own MANIFEST.SKIP. @@ -53,119 +52,137 @@ DESCRIPTION module authors are strongly encouraged to regenerate their SIGNATURE files. Users verifying old SHA1 signature files will receive a warning. - verify (...) - verify a signature file - - sign (...) - make signature file - overwrites existing one - -NAME - Module::Signature - Module signature file manipulation - VARIABLES + No package variables are exported by default. $Verbose - If true, Module::Signature will give information during processing - including gpg output. If false, Module::Signature will be as quiet - as possible as long as everything is working ok. Defaults to false. + + If true, Module::Signature will give information during processing + including gpg output. If false, Module::Signature will be as quiet as + possible as long as everything is working ok. Defaults to false. $SIGNATURE - The filename for a distribution's signature file. Defaults to - "SIGNATURE". + + The filename for a distribution's signature file. Defaults to + SIGNATURE. $AUTHOR - The key ID used for signature. If empty/null/0, "gpg"'s configured - default ID, or the most recently added key within the secret keyring - for "Crypt::OpenPGP", will be used for the signature. + + The key ID used for signature. If empty/null/0, gpg's configured + default ID, or the most recently added key within the secret keyring + for Crypt::OpenPGP, will be used for the signature. $KeyServer - The OpenPGP key server for fetching the author's public key - (currently only implemented on "gpg", not "Crypt::OpenPGP"). May be - set to a false value to prevent this module from fetching public - keys. + + The OpenPGP key server for fetching the author's public key + (currently only implemented on gpg, not Crypt::OpenPGP). May be set + to a false value to prevent this module from fetching public keys. $KeyServerPort - The OpenPGP key server port, defaults to 11371. + + The OpenPGP key server port, defaults to 11371. $Timeout - Maximum time to wait to try to establish a link to the key server. - Defaults to 3. + + Maximum time to wait to try to establish a link to the key server. + Defaults to 3. $AutoKeyRetrieve - Whether to automatically fetch unknown keys from the key server. - Defaults to 1. + + Whether to automatically fetch unknown keys from the key server. + Defaults to 1. $Cipher - The default cipher used by the "Digest" module to make signature - files. Defaults to "SHA256", but may be changed to other ciphers via - the "MODULE_SIGNATURE_CIPHER" environment variable if the SHA256 - cipher is undesirable for the user. - The cipher specified in the SIGNATURE file's first entry will be - used to validate its integrity. For "SHA256", the user needs to have - any one of these modules installed: Digest::SHA, Digest::SHA256, or - Digest::SHA::PurePerl. + The default cipher used by the Digest module to make signature files. + Defaults to SHA256, but may be changed to other ciphers via the + MODULE_SIGNATURE_CIPHER environment variable if the SHA256 cipher is + undesirable for the user. + + The cipher specified in the SIGNATURE file's first entry will be used + to validate its integrity. For SHA256, the user needs to have any one + of these modules installed: Digest::SHA, Digest::SHA256, or + Digest::SHA::PurePerl. $Preamble - The explanatory text written to newly generated SIGNATURE files - before the actual entries. + + The explanatory text written to newly generated SIGNATURE files + before the actual entries. ENVIRONMENT + Module::Signature honors these environment variables: MODULE_SIGNATURE_AUTHOR - Works like $AUTHOR. + + Works like $AUTHOR. MODULE_SIGNATURE_CIPHER - Works like $Cipher. + + Works like $Cipher. MODULE_SIGNATURE_VERBOSE - Works like $Verbose. + + Works like $Verbose. MODULE_SIGNATURE_KEYSERVER - Works like $KeyServer. + + Works like $KeyServer. MODULE_SIGNATURE_KEYSERVERPORT - Works like $KeyServerPort. + + Works like $KeyServerPort. MODULE_SIGNATURE_TIMEOUT - Works like $Timeout. + + Works like $Timeout. CONSTANTS + These constants are not exported by default. CANNOT_VERIFY (0E0) - Cannot verify the OpenPGP signature, maybe due to the lack of a - network connection to the key server, or if neither gnupg nor - Crypt::OpenPGP exists on the system. + + Cannot verify the OpenPGP signature, maybe due to the lack of a + network connection to the key server, or if neither gnupg nor + Crypt::OpenPGP exists on the system. SIGNATURE_OK (0) - Signature successfully verified. + + Signature successfully verified. SIGNATURE_MISSING (-1) - The SIGNATURE file does not exist. + + The SIGNATURE file does not exist. SIGNATURE_MALFORMED (-2) - The signature file does not contains a valid OpenPGP message. + + The signature file does not contains a valid OpenPGP message. SIGNATURE_BAD (-3) - Invalid signature detected -- it might have been tampered with. + + Invalid signature detected -- it might have been tampered with. SIGNATURE_MISMATCH (-4) - The signature is valid, but files in the distribution have changed - since its creation. + + The signature is valid, but files in the distribution have changed + since its creation. MANIFEST_MISMATCH (-5) - There are extra files in the current directory not specified by the - MANIFEST file. + + There are extra files in the current directory not specified by the + MANIFEST file. CIPHER_UNKNOWN (-6) - The cipher used by the signature file is not recognized by the - "Digest" and "Digest::*" modules. + + The cipher used by the signature file is not recognized by the Digest + and Digest::* modules. NOTES - Signing your module as part of "make dist" + + Signing your module as part of make dist + The easiest way is to use Module::Install: sign; # put this before "WriteAll" @@ -185,20 +202,22 @@ NOTES # ... original arguments ... )->create_build_script; - MANIFEST.SKIP Considerations + MANIFEST.SKIP Considerations + (The following section is lifted from Iain Truskett's Test::Signature module, under the Perl license. Thanks, Iain!) It is imperative that your MANIFEST and MANIFEST.SKIP files be accurate - and complete. If you are using "ExtUtils::MakeMaker" and you do not have - a MANIFEST.SKIP file, then don't worry about the rest of this. If you do - have a MANIFEST.SKIP file, or you use "Module::Build", you must read + and complete. If you are using ExtUtils::MakeMaker and you do not have + a MANIFEST.SKIP file, then don't worry about the rest of this. If you + do have a MANIFEST.SKIP file, or you use Module::Build, you must read this. - Since the test is run at "make test" time, the distribution has been - made. Thus your MANIFEST.SKIP file should have the entries listed below. + Since the test is run at make test time, the distribution has been + made. Thus your MANIFEST.SKIP file should have the entries listed + below. - If you're using "ExtUtils::MakeMaker", you should have, at least: + If you're using ExtUtils::MakeMaker, you should have, at least: #defaults ^Makefile$ @@ -207,29 +226,30 @@ NOTES ^blibdirs These entries are part of the default set provided by - "ExtUtils::Manifest", which is ignored if you provide your own + ExtUtils::Manifest, which is ignored if you provide your own MANIFEST.SKIP file. - If you are using "Module::Build", you should have two extra entries: + If you are using Module::Build, you should have two extra entries: ^Build$ ^_build/ - If you don't have the correct entries, "Module::Signature" will complain + If you don't have the correct entries, Module::Signature will complain that you have: ==> MISMATCHED content between MANIFEST and distribution files! <== You should note this during normal development testing anyway. - Testing signatures + Testing signatures + You may add this code as t/0-signature.t in your distribution tree: #!/usr/bin/perl - + use strict; print "1..1\n"; - + if (!$ENV{TEST_SIGNATURE}) { print "ok 1 # skip Set the environment variable", " TEST_SIGNATURE to enable this test\n"; @@ -251,21 +271,22 @@ NOTES or print "not "; print "ok 1 # Valid signature\n"; } - + __END__ If you are already using Test::More for testing, a more straightforward version of t/0-signature.t can be found in the Module::Signature distribution. - Note that "MANIFEST.SKIP" is considered by default only when + Note that MANIFEST.SKIP is considered by default only when $ENV{TEST_SIGNATURE} is set to a true value. - Also, if you prefer a more full-fledged testing package, and are willing - to inflict the dependency of Module::Build on your users, Iain + Also, if you prefer a more full-fledged testing package, and are + willing to inflict the dependency of Module::Build on your users, Iain Truskett's Test::Signature might be a better choice. SEE ALSO + Digest, Digest::SHA, Digest::SHA::PurePerl ExtUtils::Manifest, Crypt::OpenPGP, Test::Signature @@ -275,25 +296,18 @@ SEE ALSO Dist::Zilla::Plugin::Signature AUTHORS + Audrey Tang LICENSE + This work is under a CC0 1.0 Universal License, although a portion of the documentation (as detailed above) is under the Perl license. - To the extent possible under law, 唐鳳 has waived all copyright and + To the extent possible under law, 唐鳳 has waived all copyright and related or neighboring rights to Module-Signature. This work is published from Taiwan. - - -AUTHOR - Audrey Tang - -COPYRIGHT AND LICENSE - This software is copyright (c) 2024 by waved. - - This is free software; you can redistribute it and/or modify it under - the same terms as the Perl 5 programming language system itself. + http://creativecommons.org/publicdomain/zero/1.0 diff --git a/cpanfile b/cpanfile index ed5dabd..238c733 100644 --- a/cpanfile +++ b/cpanfile @@ -1,35 +1,16 @@ # Do not edit this file directly. To change prereqs, edit the `dist.ini` file. -requires "Crypt::OpenPGP" => "0"; -requires "Crypt::OpenPGP::KeyServer" => "0"; -requires "Exporter" => "0"; -requires "ExtUtils::Manifest" => "0"; -requires "File::Spec" => "0"; requires "File::Temp" => "0"; -requires "IO::Socket::INET" => "0"; -requires "Text::Diff" => "0"; -requires "constant" => "0"; requires "perl" => "5.010"; -requires "strict" => "0"; -requires "vars" => "0"; -requires "version" => "0"; -requires "warnings" => "0"; -on 'test' => sub { - requires "Data::Dumper" => "0"; - requires "File::Basename" => "0"; - requires "File::Path" => "0"; - requires "FindBin" => "0"; - requires "Getopt::Long" => "0"; +on 'build' => sub { + requires "ExtUtils::MakeMaker" => "6.36"; requires "IPC::Run" => "0"; - requires "Pod::Usage" => "0"; - requires "Socket" => "0"; requires "Test::More" => "0"; - requires "lib" => "0"; }; on 'configure' => sub { - requires "ExtUtils::MakeMaker" => "0"; + requires "ExtUtils::MakeMaker" => "6.36"; }; on 'develop' => sub { diff --git a/dist.ini b/dist.ini index 92f4e35..e7b2f96 100644 --- a/dist.ini +++ b/dist.ini @@ -8,23 +8,35 @@ license = Perl_5 [Meta::Maintainers] maintainer = Timothy Legge +[MakeMaker::Awesome] +header_file = maint/Makefile_header.PL +WriteMakefile_arg = %args +WriteMakefile_arg = PREREQ_PM => {%{$WriteMakefileArgs{PREREQ_PM}}, %requires} +;footer = use Data::Dumper; print STDERR Dumper(\%args); print STDERR Dumper(\%WriteMakefileArgs); + [Git::Contributors] -[AutoPrereqs] [Prereqs / RuntimeRequires] perl = 5.010 -Crypt::OpenPGP = 0 +File::Temp = 0 [Prereqs / TestRequires] +[Prereqs / BuildRequires] +ExtUtils::MakeMaker = 6.36 +IPC::Run = 0 +Test::More = 0 + +[Prereqs / ConfigureRequires] +ExtUtils::MakeMaker = 6.36 + [PruneCruft] [ManifestSkip] [MetaYAML] -[Pod2Readme] +[ReadmeFromPod] [ExtraTests] [ExecDir] [ShareDir] -[MakeMaker] [TestRelease] [ConfirmRelease] [Manifest] @@ -38,10 +50,6 @@ exclude_filename = MANIFEST exclude_filename = README exclude_filename = SECURITY.md -[Encoding] -encoding = bytes -match = ico - [CPANFile] [CopyFilesFromBuild::Filtered] diff --git a/lib/Module/Signature.pm b/lib/Module/Signature.pm index 7107838..e059aa7 100644 --- a/lib/Module/Signature.pm +++ b/lib/Module/Signature.pm @@ -73,12 +73,6 @@ sub _cipher_map { return \%map; } -=head2 verify (...) - -verify a signature file - -=cut - sub verify { my %args = ( skip => $ENV{TEST_SIGNATURE}, @_ ); my $rv; @@ -403,12 +397,6 @@ sub _compare { return SIGNATURE_MISMATCH; } -=head2 sign (...) - -make signature file - overwrites existing one - -=cut - sub sign { my %args = ( skip => 1, @_ ); my $overwrite = $args{overwrite}; @@ -1022,6 +1010,8 @@ Iain Truskett's B might be a better choice. =cut +=for Pod::Coverage sign verify + =head1 SEE ALSO L, L, L diff --git a/maint/Makefile_header.PL b/maint/Makefile_header.PL new file mode 100644 index 0000000..6529074 --- /dev/null +++ b/maint/Makefile_header.PL @@ -0,0 +1,215 @@ +use FindBin '$Bin'; +use lib $Bin; + +$|++; +my %requires; +my %args; +$args{LICENSE} = 'unrestricted'; +# clean generated test files +$args{clean} = {FILES => "t/test-dat*"}; + +# On Win32 (excluding cygwin) we know that IO::Socket::INET, +# which is needed for keyserver stuff, doesn't work. In fact +# it potentially hangs forever. So bail out with a N/A on +# Win32. +if ( $^O eq 'MSWin32' and 0 ) { + print "Keyserver behaviour is dangerous unreliable on Win32\n"; + print "Not installing on this platform.\n"; + exit(255); +} else { + $requires{'IO::Socket::INET'} = 0; +} + +# We will need something to handle SHA1/256 +unless ( + can_use('Digest::SHA') or + can_use('Digest::SHA::PurePerl') or + (can_use('Digest::SHA1') and can_use('Digest::SHA256')) +) { + # Nothing installed, we need to install a digest module + if ( can_cc() ) { + $requires{'Digest::SHA'} = 0; + } else { + $requires{'Digest::SHA::PurePerl'} = 0; + } +} + +# Is openpgp currently installed +if ( can_use ('Crypt::OpenPGP') ) { + # Crypt::OpenPGP installed/available, continue on... +} elsif ( my $gpg = locate_gpg() ) { + # We SHOULD have gpg, double-check formally + requires_external_bin ($gpg); +} elsif ( can_cc() and $ENV{AUTOMATED_TESTING} ) { + # Dive headlong into a full Crypt::OpenPGP install. + $requires{'Crypt::OpenPGP'} = 0; +} else { + # Ask the user what to do + ask_user(); +} + +unless ( can_run('diff') ) { + # We know Text::Diff fails on Cygwin (for now) + if ( $^O ne 'Cygwin' ) { + $requires{'Algorithm::Diff'} = 0; + $requires{'Text::Diff'} = 0; + } + } + +##################################################################### +# Support Functions + +sub locate_gpg { + print "Looking for GNU Privacy Guard (gpg), a cryptographic signature tool...\n"; + + my ($gpg, $gpg_path); + for my $gpg_bin ('gpg', 'gpg2', 'gnupg', 'gnupg2') { + $gpg_path = can_run($gpg_bin); + next unless $gpg_path; + next unless `$gpg_bin --version` =~ /GnuPG/; + next unless defined `$gpg_bin --list-public-keys`; + + $gpg = $gpg_bin; + last; + } + unless ( $gpg ) { + print "gpg not found.\n"; + return; + } + + print "GnuPG found ($gpg_path).\n"; + + return 1 if grep { /^--installdeps/} @ARGV; + + if ( prompt("Import PAUSE and author keys to GnuPG?", 'y' ) =~ /^y/i) { + print 'Importing... '; + system $gpg, '--quiet', '--import', qw[ AUDREYT2018.pub ANDK2020.pub PAUSE2022.pub NIKLASHOLM2018.pub TIMLEGGE2024.pub ]; + print "done.\n"; + } + + return $gpg; +} + +sub ask_user { + + # Defined the prompt messages + my $message1 = <<'END_MESSAGE'; + +Could not auto-detect a signature utility on your system. + +What do you want me to do? + +1) Let you install GnuPG manually while I'm waiting for your answer; + it is available at http://www.gnupg.org/download/ or may be available + from your platforms packaging system (for Open Source platforms). + +END_MESSAGE + + my $message2 = <<'END_MESSAGE'; + +2) Automatically install Crypt::OpenPGP and the 20 modules it requires + from CPAN, which will give the same functionality as GnuPG. + +END_MESSAGE + + # Present the options + print $message1; + + my $option3 = 2; + if ( can_cc() ) { + $option3 = 3; + print $message2; + } + + print <<"END_MESSAGE"; + +$option3) Forget this cryptographic signature stuff for now. + +END_MESSAGE + + my $choice; + foreach ( 1 .. 3 ) { + $choice = prompt("Your choice:", 3) || 3; + last if $choice =~ /^[123]$/; + print "Sorry, I cannot understand '$choice'.\n" + } + + if ( $choice == 1 ) { + # They claim to have installed gpg + requires_external_bin ('gpg'); + } elsif ( $choice == 2 and $option3 == 3 ) { + # They want to install Crypt::OpenPGP + $requires{'Crypt::OpenPGP'} = 0; + } else { + # Forget about it... + print "Module::Signature is not wanted on this host.\n"; + exit(0); + } +} + +# check if we can load some module +### Upgrade this to not have to load the module if possible +sub can_use { + my ($mod, $ver) = @_; + $mod =~ s{::|\\}{/}g; + $mod .= '.pm' unless $mod =~ /\.pm$/i; + my $pkg = $mod; + $pkg =~ s{/}{::}g; + $pkg =~ s{\.pm$}{}i; + local $@; + eval { require $mod; $pkg->VERSION($ver || 0); 1 }; +} + +# Check if we can run some command +sub can_run { + my ($cmd) = @_; + my $_cmd = $cmd; + return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); + for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { + next if $dir eq ''; + require File::Spec; + my $abs = File::Spec->catfile($dir, $cmd); + return $abs if (-x $abs or $abs = MM->maybe_command($abs)); + } + return; +} +# Can we locate a (the) C compiler +sub can_cc { + if ($^O eq 'VMS') { + require ExtUtils::CBuilder; + my $builder = ExtUtils::CBuilder->new( + quiet => 1, + ); + return $builder->have_compiler; + } + my @chunks = split(/ /, $Config::Config{cc}) or return; + # $Config{cc} may contain args; try to find out the program part + while (@chunks) { + return can_run("@chunks") || (pop(@chunks), next); + } + return; +} + +sub requires_external_bin { + my ($bin, $version) = @_; + if ( $version ) { + die "requires_external_bin does not support versions yet"; + } + # Load the package containing can_run early, + # to avoid breaking the message below. + # Locate the bin + print "Locating bin:$bin..."; + my $found_bin = can_run( $bin ); + if ( $found_bin ) { + print " found at $found_bin.\n"; + } else { + print " missing.\n"; + print "Unresolvable missing external dependency.\n"; + print "Please install '$bin' seperately and try again.\n"; + print STDERR "NA: Unable to build distribution on this platform.\n"; + exit(0); + } + # Once we have some way to specify external deps, do it here. + # In the mean time, continue as normal. + 1; +}