#! /usr/bin/perl

use IO::File;
use File::Temp qw(tempdir);
use strict;
use warnings;
use Getopt::Long;
use POSIX qw(uname);

my $dry_run;
my $usage;

my $keys = "/etc/yum.repos.d";

GetOptions ("dry-run" => \$dry_run,
	    "usage" => \$usage,
	    "help" => \$usage)
    or die("Error in command line arguments\n");

if ($usage)
{
    print "Usage: $0 [--dry-run]\n\n";
    print "    Removes all RPM PGP keys except the ones from $keys\n";
    exit(0);
}

my $releasever = IO::File->new;

open($releasever, "-|",
     "rpm",
     "-q",
     '--queryformat=%{VERSION}\n',
     "--whatprovides",
     "fedora-release-common");

my $version = <$releasever>;
close($releasever)
    or die "Cannot read fedora-release-common version\n";
chomp $version;

my $arch = [ POSIX::uname ]->[4];

my $dir = tempdir(CLEANUP => 1);

chmod(0700, $dir);

my $gpg = "gpg2";

my %gpgkeys;

foreach my $key (sort glob("$keys/*.repo"))
{
    my $fh = IO::File->new($key, "r");

    my $repository = {};
    my $repository_name = "";

    while (defined(my $line=<$fh>))
    {
	chomp $line;

	if ($line =~ /^\[/)
	{
	    $repository = {};
	    $repository_name = $line;

	    $repository_name =~ s/[\s\[\]]//g;
	}

	if ($line =~ /(.*)=(.*)/)
	{
	    $repository->{$1} = $2;
	}
	next unless $line =~ s/^gpgkey=//;

	foreach my $url (split(/\s+/, $line))
	{
	    die "gpgkey in $key is using an unsupported URL\n"
		unless $url =~ m@^file:///@
		|| $url =~ m@^https?://@;

	    $url =~ s@\$releasever@$version@g;
	    $url =~ s@\$basearch@$arch@g;

	    push @{$gpgkeys{$url} //= []}, {
		file => $key,
		name => $repository_name,
		meta => $repository,
	    };
	}
    }
}

foreach my $file (sort keys %gpgkeys)
{
    my $fh = IO::File->new;

    my $info = $gpgkeys{$file};

    print "Downloading $file for:\n";

    foreach my $source (sort {
	$a->{name} cmp $b->{name} ||
	    $a->{file} cmp $b->{file}
	} @$info)
    {
	my $name =
	    $source->{meta}{name} // $source->{name};

	$name =~ s@\$releasever@$version@g;
	$name =~ s@\$basearch@$arch@g;

	print "  $name (" . $source->{file} . ")\n";
    }

    system("curl",
	"-o",
	"$dir/tmpimportkey.gpg",
	"--silent",
	"--show-error",
        "--location",
	$file) == 0 or die "Could not execute curl\n";

    system($gpg, "--homedir",
	$dir,
	"--quiet",
	"--import",
	"$dir/tmpimportkey.gpg"
	) == 0 or die "Could not import $file";
}

my $count_keys = sub {

    my $fh = IO::File->new;

    open($fh, "-|",
	$gpg, "--homedir", $dir, "--list-keys", "--with-colons");

    my $counter = 0;

    ++$counter for <$fh>;

    return $counter;
};

my $n_keys = $count_keys->();

my @packages;
my %descr;

{
    my $fh = IO::File->new;

    open($fh, "-|", "rpmkeys", "--list");

    while (defined(my $p=<$fh>))
    {
	chomp $p;

	if ($p =~ /([^\s]+)\s+(.*)/)
	{
	    $descr{$1} = $2;
	    push @packages, $1;
	}
    }
}

my $removed_counter = 0;

foreach my $p (@packages)
{
    my $key = IO::File->new;

    my $gpg_imp = IO::File->new;

    open($key, "-|", "rpmkeys", "--export", "$p");

    open($gpg_imp, "|-", $gpg, "--homedir", $dir, "--quiet", "--import");

    while (defined(my $line=<$key>))
    {
	print $gpg_imp $line;
    }

    die "Cannot import PGP key from $p\n"
	unless close($key) && $? == 0 && close($gpg_imp) && $? == 0;

    my $n_now_keys = $count_keys->();

    if ($n_now_keys != $n_keys)
    {
	print(($dry_run ? "Would've removed" : "Removing") . " "
	    . $descr{$p} . "\n");

	++$removed_counter;
	unless ($dry_run)
	{
	    system("rpmkeys",
		   "--delete",
		   $p) == 0
		or die "Cannot remove $p\n";
	}
	$n_keys = $n_now_keys;
    }
}

print "Total affected keys: $removed_counter\n";
