#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - autofixer2/mysql_gpg_key                Copyright 2023 cPanel, L.L.C.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

package autofixer2::mysql_gpg_key;

use strict;
use warnings;
use Carp;
use HTTP::Tiny;
use File::Temp;
use Cpanel::SafeRun::Errors;
use Cpanel::SafeRun::Simple;

use Cpanel::FindBin ();
use Cpanel::OS      ();

BEGIN { unshift @INC, '/usr/local/cpanel'; }

my ( $new_key_url,     $new_key_file, )   = ( 'https://repo.mysql.com/RPM-GPG-KEY-mysql-2023', '/etc/pki/rpm-gpg/RPM-GPG-KEY-mysql-2023', );
my ( $old_key_url,     $old_key_file, )   = ( 'https://repo.mysql.com/RPM-GPG-KEY-MySQL-2022', '/etc/pki/rpm-gpg/RPM-GPG-KEY-mysql-2022', );
my ( $ubuntu_key_file, $ubuntu_keyring, ) = ( '/etc/apt/trusted.gpg.d/mysql-2023.gpg',         '/etc/apt/keyrings/mysql-keyring.gpg', );

my @rhel_repos      = glob('/etc/yum.repos.d/Mysql*.repo');
my @community_repos = ( '/etc/yum.repos.d/mysql-community-source.repo', '/etc/yum.repos.d/mysql-community.repo', );

exit run() unless caller;

sub run {

    return 0 unless supported_on_this_major( 109, 118 );    # Set this to the Min/Max we support this autofixer on.

    my ( $old_gpgkey_line, $old_gpgkey_uri, $new_gpgkey_line, $new_gpgkey_uri, );
    if ( grep { -f $_ } @rhel_repos ) {                     # Centos
        $old_gpgkey_uri  = $old_key_url;
        $old_gpgkey_line = quotemeta "gpgkey=$old_key_url";
        $new_gpgkey_uri  = $new_key_url;
        $new_gpgkey_line = "gpgkey=$new_gpgkey_uri";
    }
    elsif ( grep { -f $_ } @community_repos ) {             # CloudLinux
        $old_gpgkey_uri  = "file://$old_key_file";
        $old_gpgkey_line = quotemeta "gpgkey=$old_gpgkey_uri";
        $new_gpgkey_uri  = "file://$new_key_file";
        $new_gpgkey_line = "gpgkey=$new_gpgkey_uri";

        # and, retrieve the keyfile

        my $gpgkey_req = HTTP::Tiny->new()->mirror( $new_key_url, $new_key_file, );
        croak "Failed [resp status: " . $gpgkey_req->{status} . "]!\n" unless $gpgkey_req->{success};
    }

    if ( Cpanel::OS::is_yum_based() ) {
        foreach my $repo_file ( @rhel_repos, @community_repos, ) {
            next if !-f $repo_file;
            open( my $repo_fh, '<', $repo_file ) or croak "Cannot open $repo_file for reading: $!\n";
            my @repo_contents = (<$repo_fh>);
            close($repo_fh);
            open( my $repo_fh_out, '>', $repo_file ) or croak "Cannot open $repo_file for writing: $!\n";
            foreach my $line (@repo_contents) {
                $line =~ s/$old_gpgkey_line/$new_gpgkey_line\n       $old_gpgkey_uri/;
                print {$repo_fh_out} $line;
            }
            close($repo_fh_out);
        }

        # Also add to rpm keyring.
        require Cpanel::Pkgr;                         # Available on 110,118
        Cpanel::Pkgr::add_repo_keys($new_key_url);    # Locks properly.
    }
    else {
        require Cpanel::SafeDir::MK;
        require File::Basename;
        Cpanel::SafeDir::MK::safemkdir_or_die( File::Basename::dirname($ubuntu_key_file) );
        Cpanel::SafeDir::MK::safemkdir_or_die( File::Basename::dirname($ubuntu_keyring) );
        my $tmp_keyfile = download_key($new_key_url);

        # apt-key is being deprecated.
        my $apt_key        = Cpanel::FindBin::findbin('apt-key');
        my $apt_key_output = Cpanel::SafeRun::Simple::saferun( $apt_key, 'add', $tmp_keyfile );
        print "$apt_key_output\n";

        # In order to support apt-key deprecation, we are saving the key to a standalone trust file.
        my $gpg        = Cpanel::FindBin::findbin('gpg');
        my $gpg_output = Cpanel::SafeRun::Simple::saferun( $gpg, '--yes', '--output', $ubuntu_key_file, '--dearmor', $tmp_keyfile, );
        print "$gpg_output\n";

        # We are also importing the key into a keyring specifically for mysql packages.
        my $gpg_keyring_output = Cpanel::SafeRun::Simple::saferun( $gpg, '--no-default-keyring', '--keyring', "gnupg-ring:$ubuntu_keyring", '--import', $tmp_keyfile, );
        print "$gpg_keyring_output\n";

        # Also importing the old key into the mysql keyring for good measure.
        my $tmp_old_keyfile = download_key($old_key_url);
        $gpg_keyring_output = Cpanel::SafeRun::Simple::saferun( $gpg, '--no-default-keyring', '--keyring', "gnupg-ring:$ubuntu_keyring", '--import', $tmp_old_keyfile, );
        print "$gpg_keyring_output\n";

        unlink $tmp_keyfile     or warn "Could not unlink $tmp_keyfile: $!";
        unlink $tmp_old_keyfile or warn "Could not unlink $tmp_old_keyfile: $!";
    }

    return 0;    # exit(0);
}

sub download_key {
    my ( $url, ) = @_;
    my ( $fh, $tmp_file ) = File::Temp::tempfile( "AUTOFIXSQL_XXXXXXX", TMPDIR => 1, UNLINK => 1, DIR => '/root' );
    my $gpgkey_req = HTTP::Tiny->new()->get($url);
    my $gpgkey     = $gpgkey_req->{'content'};
    open( my $key_fh_w, '>', $tmp_file ) or croak "Cannot open $tmp_file: $!";
    print {$key_fh_w} $gpgkey            or croak "Cannot write to $tmp_file: $!";
    close($key_fh_w)                     or croak "Cannot close $tmp_file: $!";

    croak "Failed [resp status: " . $gpgkey_req->{status} . "]!\n" unless $gpgkey_req->{success};
    return $tmp_file;
}

sub supported_on_this_major {
    my ( $min_ver, $max_ver ) = @_;

    my $major = get_major_version();

    return 0 if $major < $min_ver;
    return 0 if $major > $max_ver;

    return 1;
}

sub get_major_version {
    my $major_version;

    if ( open( my $fh, '<', '/usr/local/cpanel/version' ) ) {
        my $full_version = <$fh>;
        chomp $full_version;
        close($fh);
        ($major_version) = $full_version =~ /^[0-9]+\.([0-9]+)/;
    }

    # Safe default.
    return $major_version || 30;
}

1;
