#!/usr/local/cpanel/3rdparty/bin/perl

# cpanel - autofixer2/update_sectigo_cabundles     Copyright 2020 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

use strict;
use warnings;

use Try::Tiny;

use Whostmgr::ACLS                    ();
use Cpanel::Apache::TLS               ();
use Cpanel::SSLInstall                ();
use Cpanel::Apache::TLS::Index        ();
use Cpanel::SSL::Objects::Certificate ();
use Cpanel::SSL::Objects::CABundle    ();
use Cpanel::AcctUtils::DomainOwner    ();

local $| = 1;

update_sectigo_cabundles();

sub update_sectigo_cabundles {

    #Needed for Cpanel::SSLInstall to be happy.
    local $ENV{'REMOTE_USER'} = 'root';
    local %Whostmgr::ACLS::ACL;
    Whostmgr::ACLS::init_acls();

    my $apache_tls_idx = Cpanel::Apache::TLS::Index->new();
    my $all_records    = $apache_tls_idx->get_all_ar();
    my %vhost_record   = map { $_->{'vhost_name'} => $_ } @$all_records;

    foreach my $vhost_name ( sort keys %vhost_record ) {
        print "Checking $vhost_name...";
        try {
            _update_vhost_if_needed($vhost_name);
            print "Done\n";
        }
        catch {
            warn "Failed to check vhost: $vhost_name: $_";
        };
    }

    return;
}

sub _update_vhost_if_needed {
    my ($vhost_name) = @_;

    # nobody is the user for unowned domains (Cpanel::SSLInstall::USER_FOR_UNOWNED_DOMAINS)
    # the constant was added in CPANEL-19457 - Thu Mar 29 14:02:17 2018 -0500 so it won't
    # be in older versions
    my $domainowner = Cpanel::AcctUtils::DomainOwner::getdomainowner( $vhost_name, { default => 'nobody' } );

    my ( $key, $crt, @cab ) = Cpanel::Apache::TLS->get_tls($vhost_name);
    return if !$key || !$crt || !@cab;

    my $cert = Cpanel::SSL::Objects::Certificate->new( 'cert' => $crt );

    # If the cert itself is expired do not update it
    # as we don't want to reinstall expired certs,
    # only certs with an expired cert in the chain.
    return if $cert->expired();

    my $cabundle = Cpanel::SSL::Objects::CABundle->new( 'cab' => join( "\n", @cab ) );
    my ( $ok, $ordered_ar ) = $cabundle->get_chain();

    # If the sectigo, comodo, or addtrust cert
    # in the chain is expired, do a reinstall.
    my $replace = 0;
    foreach my $cert (@$ordered_ar) {
        if ( $cert->expired() && $cert->issuer_text() =~ m{sectigo|comodo|addtrust}i ) {
            $replace = 1;
            last;
        }
    }

    return if !$replace;

    print "\tUpdating cabundle for “$vhost_name”....";

    # A reinstall will fetch the latest CAB from
    # the caissuers so we don't need to pass in a
    # new cab since Secitgo has now updated the caissuers
    # one.
    my $install = Cpanel::SSLInstall::real_installssl(
        domain          => $vhost_name,
        key             => $key,
        crt             => $crt,
        installing_user => $domainowner,
    );

    print "$install->{message}.\n";

    die $install->{message} if !$install->{status};

    return;
}
