#!/usr/local/cpanel/3rdparty/bin/perl # gniza WHM Plugin — Restore # Step-by-step restore workflow with dynamic dropdowns use strict; use warnings; use lib '/usr/local/cpanel/whostmgr/docroot/cgi/gniza-whm/lib'; use Whostmgr::HTMLInterface (); use Cpanel::Form (); use GnizaWHM::Config; use GnizaWHM::Runner; use GnizaWHM::UI; my $form = Cpanel::Form::parseform(); my $method = $ENV{'REQUEST_METHOD'} // 'GET'; my $step = $form->{'restore_step'} // '1'; my %TYPE_LABELS = ( account => 'Full Account', files => 'Files', database => 'Database', mailbox => 'Mailbox', cron => 'Cron Jobs', dbusers => 'Database Users & Grants', cpconfig => 'Panel Config', domains => 'Domains', ssl => 'SSL Certificates', ); my %SIMPLE_TYPES = map { $_ => 1 } qw(account cron cpconfig); if ($step eq 'fetch_options') { handle_fetch_options() } elsif ($step eq 'fetch_accounts') { handle_fetch_accounts() } elsif ($step eq '2') { handle_step2() } elsif ($step eq '3') { handle_step3() } elsif ($step eq '4') { handle_step4() } else { handle_step1() } exit; # ── Helpers ─────────────────────────────────────────────────── sub _uri_escape { my $str = shift // ''; $str =~ s/([^A-Za-z0-9\-._~])/sprintf("%%%02X", ord($1))/ge; return $str; } # ── JSON endpoint: fetch database/mailbox options ───────────── sub handle_fetch_options { my $remote = $form->{'remote'} // ''; my $account = $form->{'account'} // ''; my $timestamp = $form->{'timestamp'} // ''; my $type = $form->{'type'} // ''; print "Content-Type: application/json\r\n\r\n"; if ($remote eq '' || $account eq '' || $timestamp eq '' || $type eq '') { print qq({"error":"Missing required parameters"}); return; } my $subcmd; my %extra_opts; if ($type eq 'database') { $subcmd = 'list-databases' } elsif ($type eq 'mailbox') { $subcmd = 'list-mailboxes' } elsif ($type eq 'dbusers') { $subcmd = 'list-dbusers' } elsif ($type eq 'cron') { $subcmd = 'list-cron' } elsif ($type eq 'domains') { $subcmd = 'list-dns' } elsif ($type eq 'ssl') { $subcmd = 'list-ssl' } elsif ($type eq 'files') { $subcmd = 'list-files'; my $path = $form->{'path'} // ''; $extra_opts{path} = $path if $path ne ''; } else { print qq({"error":"Invalid type"}); return; } my ($ok, $stdout, $stderr) = GnizaWHM::Runner::run( 'restore', $subcmd, [$account], { remote => $remote, timestamp => $timestamp, %extra_opts } ); unless ($ok) { my $msg = $stderr // 'Failed to list options'; $msg =~ s/\\/\\\\/g; $msg =~ s/"/\\"/g; $msg =~ s/\n/\\n/g; $msg =~ s/\r/\\r/g; print qq({"error":"$msg"}); return; } my @options; for my $line (split /\n/, $stdout) { $line =~ s/^\s+|\s+$//g; next unless $line ne ''; push @options, $line; } # Build JSON array manually (no JSON module dependency) my $json_arr = join(',', map { my $v = $_; $v =~ s/\\/\\\\/g; $v =~ s/"/\\"/g; qq("$v") } @options); print qq({"options":[$json_arr]}); } # ── JSON endpoint: fetch accounts from remote ────────────────── sub handle_fetch_accounts { my $remote = $form->{'remote'} // ''; print "Content-Type: application/json\r\n\r\n"; if ($remote eq '') { print qq({"error":"Remote is required"}); return; } my ($ok, $stdout, $stderr) = GnizaWHM::Runner::run( 'list', 'accounts', [], { remote => $remote } ); unless ($ok) { my $msg = $stderr // 'Failed to list accounts'; $msg =~ s/\\/\\\\/g; $msg =~ s/"/\\"/g; $msg =~ s/\n/\\n/g; $msg =~ s/\r/\\r/g; print qq({"error":"$msg"}); return; } # Get local cPanel accounts for terminated detection my %local_accounts = map { $_ => 1 } GnizaWHM::UI::get_cpanel_accounts(); my @accounts; for my $line (split /\n/, $stdout) { $line =~ s/^\s+|\s+$//g; next unless $line =~ /^[a-z][a-z0-9_-]*$/; my $terminated = $local_accounts{$line} ? 0 : 1; $line =~ s/\\/\\\\/g; $line =~ s/"/\\"/g; push @accounts, qq({"name":"$line","terminated":$terminated}); } print '{"accounts":[' . join(',', @accounts) . ']}'; } # ── Step 1: Select Account + Remote ───────────────────────── sub handle_step1 { print "Content-Type: text/html\r\n\r\n"; Whostmgr::HTMLInterface::defheader('GNIZA Backup Manager — Restore', '', '/cgi/gniza-whm/restore.cgi'); print GnizaWHM::UI::page_header('Restore from Backup'); print GnizaWHM::UI::render_nav('restore.cgi'); print GnizaWHM::UI::render_flash(); my @remotes = GnizaWHM::UI::list_remotes(); unless (@remotes) { print qq{
';
for (var i = 0; i < options.length; i++) {
html += options[i].replace(/&/g,'&').replace(//g,'>') + '\\n';
}
html += '';
container.innerHTML = html;
} else {
var html = '| Remote | $esc_remote |
| Account | $esc_account |
| Snapshot | $esc_timestamp |
| Restore Types | $types_display |
| Path | $path_display |
| Database | $db_display |
| Database Users | $dbu_display |
| Mailbox | $mb_display |
| Domains | $dom_display |
| SSL | $ssl_display |
| Terminate First | Yes — account will be removed before restore |
| Exclude | $exclude_display |