diff options
Diffstat (limited to 'SBO-Lib/lib/SBO/Lib/Repo.pm')
-rw-r--r-- | SBO-Lib/lib/SBO/Lib/Repo.pm | 147 |
1 files changed, 123 insertions, 24 deletions
diff --git a/SBO-Lib/lib/SBO/Lib/Repo.pm b/SBO-Lib/lib/SBO/Lib/Repo.pm index 35ed4c9..6c7babb 100644 --- a/SBO-Lib/lib/SBO/Lib/Repo.pm +++ b/SBO-Lib/lib/SBO/Lib/Repo.pm @@ -6,13 +6,17 @@ use warnings; our $VERSION = '2.7.2'; -use SBO::Lib::Util qw/ %config prompt usage_error get_slack_version get_slack_version_url script_error open_fh open_read in _ERR_DOWNLOAD /; +use SBO::Lib::Util qw/ %config prompt usage_error get_slack_version get_slack_version_key get_slack_version_url script_error open_fh open_read in _ERR_DOWNLOAD /; +use SBO::Lib::Cryptography qw/ has_valid_gpg_signature verify_gpg_signed_file VALID_SIGNATURE /; use Cwd; use File::Copy; use File::Find; +use File::Temp "tempdir"; use File::Path qw/ make_path remove_tree /; +use IPC::Open3; use Sort::Versions; +use Symbol "gensym"; use Exporter 'import'; @@ -211,9 +215,26 @@ sub generate_slackbuilds_txt { return 1; } +sub latest_git_tag { + my $version = shift; + my $tag = ''; + + open(my $std_out, "git tag |") or die("dead"); + while (my $line = <$std_out>) { + if ($line =~ /^$version-/) { + $tag = $line; + } + } + close($std_out); + + chomp($tag); + + return $tag; +} + =head2 git_sbo_tree - my $bool = git_sbo_tree($url); + my $bool = git_sbo_tree($url, $key_id); C<git_sbo_tree()> will C<git clone> the repository specified by C<$url> to the C<$repo_path> if the C<$url> repository isn't already there. If it is, it will @@ -225,28 +246,62 @@ true value. =cut sub git_sbo_tree { - script_error('git_sbo_tree requires an argument.') unless @_ == 1; + script_error('git_sbo_tree requires two arguments.') unless @_ == 2; my $url = shift; + my $key_id = shift; + my $cwd = getcwd(); - my $res; - if (-d "$repo_path/.git" and check_git_remote($repo_path, $url)) { - _race::cond '$repo_path can be deleted after -d check'; - chdir $repo_path or return 0; - $res = eval { - die unless system(qw! git fetch !) == 0; # if system() doesn't return 0, there was an error - _race::cond 'git repo could be changed or deleted here'; - die unless system(qw! git reset --hard origin !) == 0; - unlink "$repo_path/SLACKBUILDS.TXT"; - 1; - }; - } else { + + if ((! -d "$repo_path/.git") || ! check_git_remote($repo_path, $url)) { chdir $config{SBO_HOME} or return 0; + remove_tree($repo_path) if -d $repo_path; - $res = system(qw/ git clone --no-local /, $url, $repo_path) == 0; + if (system(qw/ git clone --no-local /, $url, $repo_path)) { + return 0; + } + } + + _race::cond '$repo_path can be deleted after -d check'; + chdir($repo_path) or return 0; + + return 0 unless system("git fetch") == 0; + + unlink "$repo_path/SLACKBUILDS.TXT"; + + my $git_ref = 'origin'; + my $verify_cmd = 'verify-commit'; + + my $tag = latest_git_tag(get_slack_version()); + if ($tag ne '') { + $git_ref = $tag; + $verify_cmd = 'verify-tag'; + } + + if ($key_id) { + my @output; + + print("Verifying $git_ref...\n"); + open3(undef, undef, my $std_err = gensym, "git", $verify_cmd, "--raw", "$git_ref"); + while (my $line = <$std_err>) { + push(@output, $line); + } + close($std_err); + + if (! has_valid_gpg_signature(\@output, $key_id)) { + print(STDERR "Repository GPG verification failed.\n"); + + chdir $cwd; + return 0; + } } + + _race::cond 'git repo could be changed or deleted here'; + return 0 unless system('git', 'reset', '--hard', $git_ref) == 0; + _race::cond '$cwd could be deleted here'; - return 1 if chdir $cwd and $res; - return 0; + return 0 unless chdir $cwd; + + return 1; } =head2 migrate_repo @@ -292,14 +347,26 @@ sub pull_sbo_tree { } else { unlink($slackbuilds_txt); } + + my $key_id = ''; + if ($config{GPG_KEY} ne 'FALSE') { + $key_id = $config{GPG_KEY}; + }; + my $res = 0; if ($url =~ m!^rsync://!) { - $res = rsync_sbo_tree($url); + $res = rsync_sbo_tree($url, $key_id); } else { - $res = git_sbo_tree($url); + $res = git_sbo_tree($url, $key_id); } - if ($res == 0) { warn "Could not sync from $url.\n"; exit _ERR_DOWNLOAD; } + if ($res == 0) { + warn "Could not sync from $url.\n"; + if ($url eq 'https://github.com/Ponce/slackbuilds.git' && $key_id ne '') { + warn "This URL is known not to use GPG verification. You likely want to disable with 'sboconfig --gpg-key FALSE'." + } + exit _ERR_DOWNLOAD; + } my $wanted = sub { chown 0, 0, $File::Find::name; }; find($wanted, $repo_path) if -d $repo_path; @@ -310,7 +377,7 @@ sub pull_sbo_tree { =head2 rsync_sbo_tree - my $bool = rsync_sbo_tree($url); + my $bool = rsync_sbo_tree($url, $key_id); C<rsync_sbo_tree()> syncs the SlackBuilds.org repository to C<$repo_path> from the C<$url> provided. @@ -319,14 +386,46 @@ the C<$url> provided. # rsync the sbo tree from slackbuilds.org to $repo_path sub rsync_sbo_tree { - script_error('rsync_sbo_tree requires an argument.') unless @_ == 1; + script_error('rsync_sbo_tree requires two arguments.') unless @_ == 2; + my $url = shift; $url .= '/' unless $url =~ m!/$!; # make sure $url ends with / + my $key_id = shift; + my @info; # only slackware versions above 14.1 have an rsync that supports --info=progress2 if (versioncmp(get_slack_version(), '14.1') == 1) { @info = ('--info=progress2'); } + my @args = ('rsync', @info, '-a', '--delete', $url); - return system(@args, $repo_path) == 0; + return 0 unless system(@args, $repo_path) == 0; + + my $cwd = getcwd(); + chdir($repo_path); + + if ($key_id) { + if (versioncmp(get_slack_version(), '14.1') == -1) { + print("GPG verification is not present for 14.0 and earlier. You should consider disabling GPG verification.") + } + + print("Verifying CHECKSUMS.md5...\n"); + my $res = verify_gpg_signed_file('CHECKSUMS.md5.asc', $key_id); + if ($res ne VALID_SIGNATURE) { + print(STDERR "Respository CHECKSUMS.md5 GPG verification failed.\n"); + + chdir($cwd); + return 0; + } + } + + if ( -e "CHECKSUMS.md5" ) { + print("Verifying file integrity using CHECKSUMS.md5...\n"); + if (system('tail +13 CHECKSUMS.md5 | md5sum -c --quiet -')) { + chdir($cwd); + return 0; + } + } + + return chdir($cwd); } =head2 slackbuilds_or_fetch |