__('Import'),
];
switch(grv('action')) {
case 'save':
form_save();
break;
case 'actions':
form_actions();
break;
case 'details':
package_get_details();
break;
case 'diff':
package_diff_file();
break;
case 'verify':
package_verify_key();
break;
case 'accept':
package_accept_key();
break;
default:
top_header();
package_import();
bottom_footer();
break;
}
function check_tmp_dir() : mixed {
if (is_tmp_writable()) {
return true;
} else {
?>
['regexp' => '/^([a-zA-Z0-9_]+)$/']]);
gfrv('data_source_profile');
gfrv('package_location');
gfrv('remove_orphans', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/(on)/']]);
gfrv('replace_svalues', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/(on)/']]);
if (isrv('import_state')) {
gfrv('import_state', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^[a-f0-9]{32}$/']]);
}
// ====================================================
$package_location = gfrv('package_location');
$profile_id = gfrv('data_source_profile');
$remove_orphans = isrv('remove_orphans') ? true : false;
$replace_svalues = isrv('replace_svalues') ? true : false;
$preview = false;
// A stored token carries the parameters that produced the preview. Bind every
// import-affecting input to that state so a valid token cannot be replayed with
// mismatched request values.
$import_state = false;
if (isrv('import_state')) {
$import_state = package_import_take_state(grv('import_state'));
if ($import_state === false) {
raise_message('invalid_import_state', __('The selected package import state has expired or is invalid. Please review the package and try again.'), MESSAGE_LEVEL_ERROR);
header('Location: package_import.php');
exit;
}
$package_location = $import_state['package_location'];
$profile_id = $import_state['data_source_profile'];
$remove_orphans = $import_state['remove_orphans'];
$replace_svalues = $import_state['replace_svalues'];
}
$package = json_decode(get_repo_manifest_file($package_location), true);
$manifest = $package['manifest'];
// Import Execution
if ($import_state !== false) {
$selected_items = $import_state['selected_items'];
$hashes = $import_state['selected_hashes'];
$files = $import_state['selected_files'];
$import_packages = [];
$import_hashes = [];
$import_files = [];
$import_names = [];
if (cacti_sizeof($hashes)) {
foreach ($hashes as $h) {
if (is_array($h['files'])) {
foreach ($h['files'] as $file) {
$import_hashes[$file][] = $h['hash'];
$import_packages[$file] = $file;
}
} else {
$import_hashes[$h['files']][] = $h['files'];
$import_packages[$h['files']] = $h['files'];
}
}
}
if (cacti_sizeof($files)) {
foreach ($files as $f) {
$import_files[$f['filename']][] = $f['pfile'];
$import_packages[$f['filename']] = $f['filename'];
}
}
if (cacti_sizeof($import_packages)) {
foreach ($import_packages as $filename) {
$name = 'Unknown';
if (!isset($import_names[$filename])) {
foreach ($manifest as $index => $item) {
if ($item['filename'] == $filename) {
$name = $item['name'];
$import_names[$filename] = $name;
break;
}
}
} else {
$name = $import_names[$filename];
}
if (grv('drp_action') == 1) { // Import
$data = get_repo_file($package_location, $filename);
if (isset($import_hashes[$filename]) && cacti_sizeof($import_hashes[$filename])) {
$hashes = $import_hashes[$filename];
} else {
$hashes = [];
}
if (isset($import_files[$filename]) && cacti_sizeof($import_files[$filename])) {
$files = $import_files[$filename];
} else {
$files = [];
}
if ($data !== false) {
$tmp_dir = sys_get_temp_dir() . '/package' . $_SESSION[SESS_USER_ID];
if (!is_dir($tmp_dir)) {
if (!mkdir($tmp_dir, 0777, true)) {
raise_message('tmpdir_fail', __esc('Unable to create package temporary directory %s.', $tmp_dir), MESSAGE_LEVEL_ERROR);
header('Location: package_import.php?package_location=' . $package_location);
exit;
}
}
$xmlfile = $tmp_dir . '/' . basename($filename);
file_put_contents($xmlfile, $data);
$data = import_package($xmlfile, $profile_id, $remove_orphans, $replace_svalues, $preview, false, true, $hashes, $files);
if ($data !== false && cacti_sizeof($data[0])) {
import_display_results($data[0], [], true, true);
raise_message('import_success_' . md5($xmlfile), __esc('The Package %s Imported Successfully', $name), MESSAGE_LEVEL_INFO);
} else {
raise_message('import_fail_' . md5($xmlfile), __esc('The Package %s Import Failed', $name), MESSAGE_LEVEL_ERROR);
}
unlink($xmlfile);
}
}
}
}
header('Location: package_import.php?package_location=' . $package_location);
exit;
}
// Import Confirm
$pkg_list = '';
$pkg_array = [];
$skp_list = '';
$skp_array = [];
$pkg_import_list = '';
$pkg_import_array = [];
$found_pkg_array = [];
$pkg_file_list = '';
$pkg_file_array = [];
$found_pkg_file_array = [];
$save_html = '';
// loop through each of the graphs selected on the previous page and get more info about them
foreach ($_POST as $var => $val) {
if (str_contains($var, 'chk_file_')) {
$id = base64_decode(str_replace('chk_file_', '', $var), true);
$id = json_decode((string) $id, true);
// Get rid of the basename
$id['pfile'] = str_replace(CACTI_PATH_BASE . '/', '', $id['pfile']);
$pkg_file_list .= '
' .
'' . htmle($id['package']) . ' ' .
'' . htmle($id['pfile']) . ' ' .
'';
$pkg_file_array[] = $id;
$found_pkg_file_array[$id['package']] = $id['package'];
}
if (str_contains($var, 'chk_import_')) {
$id = base64_decode(str_replace('chk_import_', '', $var), true);
$id = json_decode((string) $id, true);
$packages = explode(' ', $id['package']);
$package = '';
foreach ($packages as $index => $p) {
$package .= ($index > 0 ? ', ' : '') . htmle($p);
$found_pkg_array[$p] = $p;
}
$statuses = explode(' ', $id['status']);
$status = '';
foreach ($statuses as $index => $s) {
$status .= ($index > 0 ? ', ' : '') . htmle(ucfirst($s));
}
$pkg_import_list .= ' ' .
'' . $package . ' ' .
'' . htmle($id['type']) . ' ' .
'' . htmle($id['name']) . ' ' .
'' . $status . ' ' .
'';
$pkg_import_array[] = $id;
}
}
foreach ($_POST as $var => $val) {
if (preg_match('/^chk_package_([0-9|]+)$/', $var, $matches)) {
$package = $manifest[$matches[1]]['name'];
if (isset($found_pkg_array[$package]) || isset($found_pkg_file_array[$package])) {
$pkg_list .= '' . htmle($package) . ' ';
$pkg_array[] = $matches[1];
} else {
$skp_list .= '' . htmle($package) . ' ';
$skp_array[] = $matches[1];
}
}
}
top_header();
form_start('package_import.php');
html_start_box(__('Package %s', $actions[gnrv('drp_action')]), '60%', false, 3, 'center', '');
if (cacti_sizeof($pkg_array)) {
if (gnrv('drp_action') == '1') { // import
if ($pkg_file_list != '' || $pkg_import_list != '') {
print "
" . __n('Click \'Continue\' to Import the following Package.', 'Click \'Continue\' to Import all following Packages.', cacti_sizeof($pkg_array)) . "
";
if ($skp_list != '') {
print "
" . __n(
'The following Selected Package will be skipped as no Files or Template Items were selected.',
'The following selected Packages will be skipped as no Files or Template Items were selected.', cacti_sizeof($skp_array)) . "
";
}
if ($pkg_file_list != '') {
print '' . __('Files to be Imported') . '
';
print "
" . __('The Files in the list below will be imported.') . "
";
}
if ($pkg_import_list != '') {
print '' . __('Template Items to be Imported') . '
';
print "
" . __('The Template Items in the list below will be imported.') . "
";
}
$save_html = "" . __esc('Cancel') . " " . __esc('Continue') . ' ';
} else {
raise_message('no_selection', __('You must select either a File or a Template Item to import before proceeding'), MESSAGE_LEVEL_ERROR);
header('Location: package_import.php');
exit;
}
}
} else {
raise_message(40);
header('Location: package_import.php');
exit;
}
$import_state = package_import_store_state($pkg_array, $pkg_import_array, $pkg_file_array, [
'package_location' => $package_location,
'data_source_profile' => $profile_id,
'remove_orphans' => $remove_orphans,
'replace_svalues' => $replace_svalues,
]);
print "
" . html_hidden_input('action', 'actions') . '
' . html_hidden_input('import_state', $import_state) . '
' . html_hidden_input('drp_action', grv('drp_action')) . "
$save_html
";
html_end_box();
form_end();
bottom_footer();
}
function package_import_store_state(array $selected_items, array $selected_hashes, array $selected_files, array $context) : string {
$state_limit = 10;
$token = generate_hash();
if (!isset($_SESSION['sess_package_import_state']) || !is_array($_SESSION['sess_package_import_state'])) {
$_SESSION['sess_package_import_state'] = [];
}
$_SESSION['sess_package_import_state'][$token] = [
'selected_items' => $selected_items,
'selected_hashes' => $selected_hashes,
'selected_files' => $selected_files,
'package_location' => $context['package_location'],
'data_source_profile' => $context['data_source_profile'],
'remove_orphans' => $context['remove_orphans'],
'replace_svalues' => $context['replace_svalues'],
];
while (cacti_sizeof($_SESSION['sess_package_import_state']) > $state_limit) {
array_shift($_SESSION['sess_package_import_state']);
}
return $token;
}
function package_import_take_state(string $token) : array|false {
if ($token === '' || !isset($_SESSION['sess_package_import_state'][$token]) || !is_array($_SESSION['sess_package_import_state'][$token])) {
return false;
}
$import_state = $_SESSION['sess_package_import_state'][$token];
unset($_SESSION['sess_package_import_state'][$token]);
if (
!isset($import_state['selected_items']) ||
!isset($import_state['selected_hashes']) ||
!isset($import_state['selected_files']) ||
!is_array($import_state['selected_items']) ||
!is_array($import_state['selected_hashes']) ||
!is_array($import_state['selected_files']) ||
!isset($import_state['package_location']) ||
!isset($import_state['data_source_profile']) ||
!array_key_exists('remove_orphans', $import_state) ||
!array_key_exists('replace_svalues', $import_state)
) {
return false;
}
return $import_state;
}
function form_save() : void {
global $preview_only;
validate_request_vars();
if (isrv('save_component_import')) {
if (isset($_FILES['import_file']['tmp_name']) &&
($_FILES['import_file']['tmp_name'] != 'none') &&
($_FILES['import_file']['tmp_name'] != '')) {
// file upload
$xmlfile = $_FILES['import_file']['tmp_name'];
$_SESSION['sess_import_package'] = file_get_contents($xmlfile);
} elseif (isset($_SESSION['sess_import_package'])) {
$xmlfile = tempnam(sys_get_temp_dir(), 'package_import_');
file_put_contents($xmlfile, $_SESSION['sess_import_package']);
unset($_SESSION['sess_import_package']);
} else {
header('Location: package_import.php');
exit;
}
if (gfrv('data_source_profile') == '0') {
$import_as_new = true;
$profile_id = db_fetch_cell('SELECT id FROM data_source_profiles ORDER BY `default` DESC LIMIT 1');
} else {
$import_as_new = false;
$profile_id = grv('data_source_profile');
}
if (gnrv('preview_only') == 'on') {
$preview_only = true;
} elseif (gnrv('import_confirmed') == 'on') {
$preview_only = false;
} else {
$preview_only = true;
}
if (isrv('remove_orphans') && gnrv('remove_orphans') == 'on') {
$remove_orphans = true;
} else {
$remove_orphans = false;
}
if (isrv('replace_svalues') && gnrv('replace_svalues') == 'on') {
$replace_svalues = true;
} else {
$replace_svalues = false;
}
$hashes = [];
$files = [];
$templates = [];
// loop through each of the graphs selected on the previous page and get more info about them
foreach ($_POST as $var => $val) {
if (str_contains($var, 'chk_file_')) {
$id = base64_decode(str_replace('chk_file_', '', $var), true);
$id = json_decode((string) $id, true);
if (str_contains($id['pfile'], '/')) {
$parts = explode('/', $id['pfile']);
} elseif (str_contains($id['pfile'], '\\')) {
$parts = explode('\\', $id['pfile']);
} else {
$parts = [$id['pfile']];
}
foreach ($parts as $index => $p) {
if ($p == 'scripts') {
break;
}
if ($p == 'resource') {
break;
} else {
unset($parts[$index]);
}
}
$id['pfile'] = implode('/', $parts);
$files[] = $id['pfile'];
}
if (str_contains($var, 'chk_import_')) {
$id = base64_decode(str_replace('chk_import_', '', $var), true);
$id = json_decode((string) $id, true);
$hashes[] = $id['hash'];
}
}
if (cacti_sizeof($files) && !cacti_sizeof($hashes)) {
$hashes[] = 'dont import';
} elseif (cacti_sizeof($hashes) && !cacti_sizeof($files)) {
$files[] = 'dont import';
}
if (file_exists($xmlfile)) {
cacti_log("Importing $xmlfile");
} else {
cacti_log("Unable to import $xmlfile");
}
$package_name = import_package_get_name($xmlfile);
cacti_log('Package name is ' . $package_name);
// obtain debug information if it's set
$data = import_package($xmlfile, $profile_id, $remove_orphans, $replace_svalues, $preview_only, false, false, $hashes, $files);
if ($preview_only) {
package_prepare_import_array($templates, $files, $package_name, $xmlfile, $data);
import_display_package_data($templates, $files, $package_name, $xmlfile, $data, false);
} else {
if ($data !== false) {
raise_message('import_success_' . md5($xmlfile), __esc('The Package %s Imported Successfully', $package_name), MESSAGE_LEVEL_INFO);
} else {
raise_message('import_fail_' . md5($xmlfile), __esc('The Package %s Import Failed', $package_name), MESSAGE_LEVEL_ERROR);
}
unlink($xmlfile);
unset($_SESSION['sess_import_package']);
header('Location: package_import.php?package_location=0');
exit;
}
}
}
function package_file_get_contents(string $package_location, string $package_file, string $filename) : mixed {
$package_found = false;
if ($package_location > 0) {
$repo = json_decode(get_repo_manifest_file($package_location), true);
$manifest = $repo['manifest'];
if (cacti_sizeof($manifest)) {
foreach ($manifest as $m) {
if ($m['filename'] == $package_file) {
$author = $m['metadata']['author'];
$homepage = $m['metadata']['homepage'];
$email = $m['metadata']['email'];
$package_found = true;
break;
}
}
}
} elseif (isset($_SESSION['sess_import_package'])) {
$xmlfile = tempnam(sys_get_temp_dir(), 'package_import_');
$binary_signature = '';
file_put_contents($xmlfile, $_SESSION['sess_import_package']);
$data = import_read_package_data($xmlfile, $binary_signature, true);
$public_key = import_package_get_public_key($xmlfile);
$fdata = false;
foreach ($data['files']['file'] as $file) {
if ($file['name'] == $filename) {
$binary_signature = base64_decode($file['filesignature'], true);
$fdata = base64_decode($file['data'], true);
$ok = import_public_key_meets_minimum($public_key) ? openssl_verify((string) $fdata, (string) $binary_signature, $public_key, OPENSSL_ALGO_SHA256) : 0;
if ($ok != 1) {
$fdata = false;
}
break;
}
}
unlink($xmlfile);
return $fdata;
}
if ($package_found) {
$data = get_repo_file($package_location, $package_file, true);
if ($data !== false) {
$tmp_dir = sys_get_temp_dir() . '/package' . $_SESSION[SESS_USER_ID];
if (!is_dir($tmp_dir)) {
mkdir($tmp_dir);
}
$binary_signature = '';
$xmlfile = $tmp_dir . '/' . basename($package_file);
file_put_contents($xmlfile, $data);
$public_key = import_package_get_public_key($xmlfile);
$data = import_read_package_data($xmlfile, $binary_signature, true);
$fdata = false;
foreach ($data['files']['file'] as $file) {
if ($file['name'] == $filename) {
$binary_signature = base64_decode($file['filesignature'], true);
$fdata = base64_decode($file['data'], true);
$ok = import_public_key_meets_minimum($public_key) ? openssl_verify((string) $fdata, (string) $binary_signature, $public_key, OPENSSL_ALGO_SHA256) : 0;
if ($ok != 1) {
$fdata = false;
}
break;
}
}
unlink($xmlfile);
return $fdata;
}
}
return false;
}
function package_diff_file() : void {
$package_location = gfrv('package_location');
$package_file = grv('package_file');
$filename = grv('filename');
$target = realpath(CACTI_PATH_BASE . '/' . $filename);
$base = realpath(CACTI_PATH_BASE);
if ($target === false) {
// The package may contain files that do not exist locally yet.
// Resolve the parent directory instead and re-attach the leaf so
// the containment check below still applies.
$parent = realpath(dirname(CACTI_PATH_BASE . '/' . $filename));
$leaf = basename($filename);
if ($parent !== false && $leaf !== '.' && $leaf !== '..') {
$target = $parent . DIRECTORY_SEPARATOR . $leaf;
}
}
if ($target === false || $base === false ||
!str_starts_with($target . DIRECTORY_SEPARATOR, $base . DIRECTORY_SEPARATOR)) {
print __('Invalid filename specified.');
return;
}
$differOptions = [
'ignoreWhitespace' => true,
'ignoreCase' => false
];
$newfile = package_file_get_contents($package_location, $package_file, $filename);
if ($newfile !== false) {
$newfile = str_replace("\n\r", "\n", $newfile);
$newfile = explode("\n", $newfile);
}
$oldfile = file_get_contents($target);
if ($oldfile !== false) {
$oldfile = str_replace("\n\r", "\n", $oldfile);
$oldfile = explode("\n", $oldfile);
}
if (is_array($oldfile) && cacti_sizeof($oldfile)) {
if (is_array($newfile) && cacti_sizeof($newfile)) {
$differ = new Differ($oldfile, $newfile, $differOptions);
$renderer = RendererFactory::make('Inline');
// Jfcherng\Diff\Renderer\Html\AbstractHtml::htmlSafe() HTML-escapes every
// input line before adding its own / markup.
print '' . $renderer->render($differ) . '