#!/usr/bin/perl

#                                      Copyright 2025 WebPros International, LLC
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited.

package autorepair;

use strict;
use warnings;

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

use Cpanel::HttpRequest ();
use POSIX;

our @once;
our @daily;

exit main(@ARGV) unless caller();

sub main {
    my $major_version = get_major_version();

    # We don't autorepair 30 any more.
    return autorepair_below_32() if $major_version < 32;

    # Everything below 100 is already in the product proper. Please use current for future autofixers targeted after 100.
    build_autorepair_todo($major_version);

    # Please put fixers for 100 and above here.
    return do_autorepair();
}

sub build_autorepair_todo {
    my ($major_version) = @_;

    repair__once( $major_version, 32 => 78, 'update_older_versions' ) unless $ENV{'CPANEL_BASE_INSTALL'};
    repair__once( $major_version, 32 => 92, 'repair_fpm_ea_apache2_config_171' );
    repair_daily( $major_version, 32 => 98, 'update_gatherer_permissions' );
    repair_daily( $major_version, 56 => 70, 'disable_prelink' );
    repair_daily( $major_version, 56 => 70, 'fix_duplicate_cpanel_rpms' );
    repair_daily( $major_version, 76 => 76, 'auto_migrate_ea3_to_ea4' );                   # forced migration of EA3 to EA4 happens on version 76
    repair__once( $major_version, 56 => 86, 'ensure_libnghttp2_to_cover_oddball_repos_that_break_curl_and_yum' );
    repair__once( $major_version, 56 => 86, 'resolve_all_php_handlers_being_none' );
    repair__once( $major_version, 56 => 92, 'centos6_base_repo_is_no_more' );
    repair_daily( $major_version, 56 => 98, 'exim_cve_workaround' );
    repair__once( $major_version, 84  => 92,  'update_sectigo_cabundles' );
    repair__once( $major_version, 84  => 92,  'update_hostname_sectigo_cabundles' );
    repair__once( $major_version, 86  => 92,  'fix_mariadb_show_grants_roles' );
    repair__once( $major_version, 92  => 98,  'clean_92_cruft' );
    repair__once( $major_version, 98  => 98,  'fix_mariadb_password_expired' );
    repair__once( $major_version, 98  => 98,  'fix_failed_98_rpm_upgrade' );
    repair__once( $major_version, 94  => 100, 'update_lets_encrypt_cabundles2' );
    repair__once( $major_version, 98  => 100, 'purge_hostname_cert_csrs' );
    repair__once( $major_version, 94  => 102, 'mysql_gpg_key' );
    repair__once( $major_version, 102 => 104, 'httpdconf_missing_vhost' );
    repair__once( $major_version, 102 => 106, 'use_mariadb_archive_repo' );
    repair__once( $major_version, 82  => 108, 'fix_incomplete_user_deletes' );
    repair__once( $major_version, 86  => 110, 'mariadb_gpg_key' );
    repair__once( $major_version, 102 => 110, 'fix_kernel_cmdline_post_elevate' );
    repair__once( $major_version, 102 => 114, 'fix_cpanel_plugins_mirrors_for_ubuntu' );
    repair__once( $major_version, 109 => 118, 'mysql_gpg_key_2024' );
    repair__once( $major_version, 116 => 116, 'hidepid' );
    repair__once( $major_version, 104 => 110, 'update_elevate_script' );
    repair__once( $major_version, 48  => 120, 'set_upgrade_deferred_file_timestamp' );
    repair__once( $major_version, 109 => 120, 'correct_cl_profiles_pkg' );                 # pkg based so cpanel version isn’t a factor
    repair__once( $major_version, 70  => 120, 'disable_dead_fleetssl_repo' );
    repair__once( $major_version, 94  => 108, 'centos7_base_repo_is_no_more' );
    repair__once( $major_version, 100 => 108, 'centos7_disable_broken_repos' );
    repair__once( $major_version, 94  => 116, 'set_autossl_to_lets_encrypt_2' );
    repair__once( $major_version, 110 => 110, 'set_els_repo_ipv4_only' );
    repair__once( $major_version, 110 => 110, 'set_updates_to_110' );
    repair__once( $major_version, 110 => 130, 'fix_addon_features' );
    repair__once( $major_version, 110 => 130, 'update_outdated_packages' );

    return;
}

sub autorepair_below_32 {
    print "Not performing autorepair on obsolete system\n";
    return 0;
}

sub version_applies {
    my ( $major, $min_major, $max_major ) = @_;

    return if $major < $min_major;
    return if $major > $max_major;

    return 1;
}

sub repair__once {
    my ( $major, $min_major, $max_major, $script ) = @_;

    return unless version_applies( $major, $min_major, $max_major );

    push @once, $script;

    return;
}

sub repair_daily {
    my ( $major, $min_major, $max_major, $script ) = @_;

    return unless version_applies( $major, $min_major, $max_major );

    push @daily, $script;

    return;
}

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;
}

sub do_autorepair {
    return 0 unless scalar @once or scalar @daily;

    print "Running Auto Repair routines\n";

    chdir '/usr/local/cpanel/src' or die "Unable to chdir: $!";
    foreach my $repair (@once) {
        if ( !-e $repair ) {
            repair($repair);
        }
    }

    foreach my $repair (@daily) {
        repair($repair);
    }

    print "Finished running Auto Repair routines\n";

    return 0;
}

sub repair {
    my ($repair) = @_;
    print "Running autorepair on $repair\n";

    my $url        = 'http://' . get_update_source() . '/autofixer2/' . $repair;
    my $httpClient = Cpanel::HttpRequest->new( 'hideOutput' => 1, 'signed' => 1 );
    $httpClient->download( $url, $repair );
    if ( !-e $repair ) {
        die "Unable to fetch repair $repair: $!";
    }
    my $perl_bin = -x "/usr/local/cpanel/3rdparty/bin/perl" ? "/usr/local/cpanel/3rdparty/bin/perl" : "perl";
    system $perl_bin, $repair;
    return;
}

sub get_update_source {
    my $update_source = 'httpupdate.cpanel.net';
    my $source_file   = '/etc/cpsources.conf';
    if ( -r $source_file && -s $source_file ) {    # pull in from cpsources.conf if it's set.
        open( my $fh, "<", $source_file ) or return;
        while (<$fh>) {
            next if ( $_ !~ m/^\s*HTTPUPDATE\s*=\s*(\S+)/ );
            $update_source = "$1";
            die("HTTPUPDATE is set to '$update_source' in $source_file") if ( !$update_source );
            last;
        }
    }

    return $update_source;
}

1;
