Files
gniza4cp/whm/gniza-whm/setup.cgi
shuki f9326390d7 Convert all anchor buttons to button elements for consistent sizing
WHM styles override <a> tag padding, making anchor-based buttons
larger than native buttons. Using <button> elements everywhere
ensures uniform button sizing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 05:50:11 +02:00

124 lines
5.9 KiB
Perl

#!/usr/local/cpanel/3rdparty/bin/perl
# gniza WHM Plugin — Setup Wizard
# Step 1: SSH Key selection, then redirects to remotes.cgi and schedules.cgi
use strict;
use warnings;
use lib '/usr/local/cpanel/whostmgr/docroot/cgi/gniza-whm/lib';
use Whostmgr::HTMLInterface ();
use Cpanel::Form ();
use GnizaWHM::UI;
my $form = Cpanel::Form::parseform();
handle_step1();
exit;
# ── Step 1: SSH Key ──────────────────────────────────────────
sub handle_step1 {
print "Content-Type: text/html\r\n\r\n";
Whostmgr::HTMLInterface::defheader('gniza Setup Wizard', '', '/cgi/gniza-whm/setup.cgi');
print GnizaWHM::UI::page_header('gniza Setup Wizard');
my $keys = GnizaWHM::UI::detect_ssh_keys();
print qq{<div class="card bg-white shadow-sm border border-base-300 mb-6">\n<div class="card-body">\n};
print qq{<h2 class="card-title text-sm">Step 1: SSH Key</h2>\n};
print qq{<p>gniza uses SSH keys to connect to remote backup destinations. Select an existing key or create one first.</p>\n};
if (@$keys) {
print qq{<div class="my-4">\n};
print qq{<p><strong>Existing keys found:</strong></p>\n};
print qq{<table class="table table-zebra w-full">\n};
print qq{<thead><tr><th></th><th>Type</th><th>Path</th><th>Public Key</th></tr></thead>\n};
print qq{<tbody>\n};
my $first = 1;
for my $k (@$keys) {
my $checked = $first ? ' checked' : '';
my $pub = $k->{has_pub} ? 'Available' : 'Missing';
my $esc_path = GnizaWHM::UI::esc($k->{path});
my $esc_type = GnizaWHM::UI::esc($k->{type});
print qq{<tr>};
print qq{<td><input type="radio" class="radio radio-sm" name="selected_key" value="$esc_path" form="step1form"$checked></td>};
print qq{<td>$esc_type</td>};
print qq{<td><code>$esc_path</code></td>};
print qq{<td>$pub</td>};
print qq{</tr>\n};
$first = 0;
}
print qq{</tbody>\n</table>\n};
print qq{<div class="flex items-center gap-3 mt-3">\n};
print qq{ <input type="radio" class="radio radio-sm" name="selected_key" value="_custom" form="step1form" id="key_custom_radio">\n};
print qq{ <label for="key_custom_path">Custom path:</label>\n};
print qq{ <input type="text" class="input input-bordered input-sm w-full max-w-xs" id="key_custom_path" name="custom_key_path" form="step1form" placeholder="/root/.ssh/id_ed25519" onfocus="document.getElementById('key_custom_radio').checked=true">\n};
print qq{</div>\n};
print qq{</div>\n};
print qq{<form id="step1form" method="GET" action="remotes.cgi">\n};
print qq{<input type="hidden" name="action" value="add">\n};
print qq{<input type="hidden" name="wizard" value="1">\n};
print qq{<div class="flex gap-2 mt-4">\n};
print qq{ <button type="submit" class="btn btn-primary btn-sm" onclick="return gnizaPrepStep2()">Next: Configure Remote</button>\n};
print qq{ <button type="button" class="btn btn-ghost btn-sm" onclick="location.href='index.cgi'">Cancel</button>\n};
print qq{</div>\n};
print qq{</form>\n};
} else {
print qq{<div class="alert alert-info mb-4">No SSH keys found in <code>/root/.ssh/</code>. You need to create one first.</div>\n};
}
# Always show key generation instructions
print qq{<div class="mt-5">\n};
print qq{<p><strong>Generate a new SSH key</strong> (if needed):</p>\n};
print qq{<pre class="bg-neutral text-neutral-content p-3 rounded-lg text-sm font-mono overflow-x-auto my-2">ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N ""</pre>\n};
print qq{<p><strong>Copy the public key</strong> to the remote server:</p>\n};
print qq{<pre class="bg-neutral text-neutral-content p-3 rounded-lg text-sm font-mono overflow-x-auto my-2">ssh-copy-id -i /root/.ssh/id_ed25519.pub user\@host</pre>\n};
print qq{<p class="text-xs text-base-content/60 mt-2">Run these commands in WHM &rarr; Server Configuration &rarr; Terminal, or via SSH.</p>\n};
print qq{</div>\n};
unless (@$keys) {
print qq{<form method="GET" action="remotes.cgi" class="mt-4">\n};
print qq{<input type="hidden" name="action" value="add">\n};
print qq{<input type="hidden" name="wizard" value="1">\n};
print qq{<div class="flex items-center gap-3 mb-2.5">\n};
print qq{ <label class="w-44 font-medium text-sm" for="key_path_manual">Key path:</label>\n};
print qq{ <input type="text" class="input input-bordered input-sm w-full max-w-xs" id="key_path_manual" name="key_path" value="/root/.ssh/id_ed25519">\n};
print qq{</div>\n};
print qq{<div class="flex gap-2 mt-4">\n};
print qq{ <button type="submit" class="btn btn-primary btn-sm">Next: Configure Remote</button>\n};
print qq{ <button type="button" class="btn btn-ghost btn-sm" onclick="location.href='index.cgi'">Cancel</button>\n};
print qq{</div>\n};
print qq{</form>\n};
}
print qq{</div>\n</div>\n};
# JS to resolve selected key into key_path param
print <<'JS';
<script>
function gnizaPrepStep2() {
var form = document.getElementById('step1form');
var radios = document.querySelectorAll('input[name="selected_key"]');
var selected = '';
for (var i = 0; i < radios.length; i++) {
if (radios[i].checked) { selected = radios[i].value; break; }
}
if (selected === '_custom') {
selected = document.querySelector('input[name="custom_key_path"]').value;
}
if (!selected) { alert('Please select an SSH key.'); return false; }
var hidden = document.createElement('input');
hidden.type = 'hidden'; hidden.name = 'key_path'; hidden.value = selected;
form.appendChild(hidden);
return true;
}
</script>
JS
print GnizaWHM::UI::page_footer();
Whostmgr::HTMLInterface::footer();
}