__('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.') . "

    $pkg_file_list
    " . __('Package') . ' ' . __('File') . "
    "; } if ($pkg_import_list != '') { print '
    ' . __('Template Items to be Imported') . '
    '; print "

    " . __('The Template Items in the list below will be imported.') . "

    $pkg_import_list
    " . __('Package') . ' ' . __('Type') . ' ' . __('Name') . ' ' . __('Status') . "
    "; } $save_html = "'; } 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) . ''; // nosemgrep: cacti-request-var-echoed-unescaped } else { print 'New file does not exist'; } } else { print 'Old file does not exist'; } } function package_verify_key() : void { $package_location = gfrv('package_location'); $failed = []; if ($package_location > 0) { $package_ids = gfrv('package_ids', FILTER_VALIDATE_IS_NUMERIC_LIST); $repo = json_decode(get_repo_manifest_file($package_location), true); $manifest = $repo['manifest']; if ($package_ids != '') { $package_ids = explode(',', $package_ids); foreach ($package_ids as $package_id) { $filename = $manifest[$package_id]['filename']; $package_name = $manifest[$package_id]['name']; $data = get_repo_file($package_location, $filename, true); if ($data !== false) { $tmp_dir = sys_get_temp_dir() . '/package' . $_SESSION[SESS_USER_ID]; if (!is_dir($tmp_dir)) { mkdir($tmp_dir); } $xmlfile = $tmp_dir . '/' . basename($filename); file_put_contents($xmlfile, $data); if (!import_validate_signature($xmlfile)) { $info = import_get_package_info($xmlfile); if ($info === false) { $info = ['name' => $package_name, 'author' => '', 'email' => '']; } $failed[$package_name] = $info; } unlink($xmlfile); } else { print json_encode( [ 'title' => __('Repo File Missing or Damaged'), 'message' => __('The Repo \'%s\' is NOT Reachable at the URL Location in the package.manifest.', $package_name), 'header' => __('Something is wrong with your Package Repository'), 'status' => 'fileerror' ] ); exit; } } } } elseif (isset($_SESSION['sess_import_package'])) { $xmlfile = tempnam(sys_get_temp_dir(), 'package_import_'); file_put_contents($xmlfile, $_SESSION['sess_import_package']); if (!import_validate_signature($xmlfile)) { $info = import_get_package_info($xmlfile); if ($info === false) { $info = ['name' => __('Unknown'), 'author' => '', 'email' => '']; } $failed[$info['name']] = $info; } unlink($xmlfile); } if (cacti_sizeof($failed)) { $message = __('There are Signature Trust issues.
    '); $authors = []; $packages = []; foreach ($failed as $package) { $packages[] = $package['name']; $authors[$package['author']] = $package['email']; } foreach ($authors as $author => $email) { $message .= ($message != '' ? '
    ' : '') . __('Author: <%s> %s.
    ', htmle($author), htmle($email)); } foreach ($packages as $package) { $message .= ($message != '' ? '
    ' : '') . __('Package: %s', htmle($package)); } $message .= '

    ' . __('Press \'Ok\' to start Trusting the Signer. Press \'Cancel\' or hit escape to Cancel.'); print json_encode( [ 'title' => __('Some Packages Not Trusted'), 'message' => $message, 'status' => 'error' ] ); } else { print json_encode( [ 'title' => __('All Packages Trusted'), 'message' => __('All Package Signatures Validated'), 'status' => 'success' ] ); } } function package_accept_key() : void { // Trusting a new signer is a Package Management (realm 29) decision, // distinct from the Import Templates (realm 17) permission that gates // this page as a whole. if (!is_realm_allowed(29)) { raise_message('permission_denied'); header('Location: package_import.php'); exit; } $package_location = gfrv('package_location'); if ($package_location > 0) { $package_ids = gfrv('package_ids', FILTER_VALIDATE_IS_NUMERIC_LIST); $repo = json_decode(get_repo_manifest_file($package_location), true); $manifest = $repo['manifest']; $failed = []; if ($package_ids != '') { $package_ids = explode(',', $package_ids); foreach ($package_ids as $package_id) { $filename = $manifest[$package_id]['filename']; $package_name = $manifest[$package_id]['name']; $data = get_repo_file($package_location, $filename, true); if ($data !== false) { $tmp_dir = sys_get_temp_dir() . '/package' . $_SESSION[SESS_USER_ID]; if (!is_dir($tmp_dir)) { mkdir($tmp_dir); } $xmlfile = $tmp_dir . '/' . basename($filename); file_put_contents($xmlfile, $data); import_validate_public_key($xmlfile, true); unlink($xmlfile); } else { raise_message('repo_missing', __esc('The Repo \'%s\' is NOT Reachable at the URL Location or the package.manifest file is missing.', $repo['name']), MESSAGE_LEVEL_WARN); header('Location: package_import.php'); exit; } } } } elseif (isset($_SESSION['sess_import_package'])) { $xmlfile = tempnam(sys_get_temp_dir(), 'package_import_'); file_put_contents($xmlfile, $_SESSION['sess_import_package']); import_validate_public_key($xmlfile, true); unlink($xmlfile); } } function package_get_details() : void { $package_ids = gfrv('package_ids', FILTER_VALIDATE_IS_NUMERIC_LIST); $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 = true; $repo = json_decode(get_repo_manifest_file($package_location), true); $manifest = $repo['manifest']; if ($package_ids != '') { $package_ids = explode(',', $package_ids); $templates = []; $files = []; foreach ($package_ids as $package_id) { $filename = $manifest[$package_id]['filename']; $package_name = $manifest[$package_id]['name']; $data = get_repo_file($package_location, $filename, false); if ($data !== false) { $tmp_dir = sys_get_temp_dir() . '/package' . $_SESSION[SESS_USER_ID]; if (!is_dir($tmp_dir)) { mkdir($tmp_dir); } $xmlfile = $tmp_dir . '/' . basename($filename); file_put_contents($xmlfile, $data); $validated = import_validate_public_key($xmlfile, false); if ($validated === false) { $public_key = get_public_key(); } else { $public_key = $validated; } $data = import_package($xmlfile, $profile_id, $remove_orphans, $replace_svalues, $preview); package_prepare_import_array($templates, $files, $package_name, $filename, $data); unlink($xmlfile); } else { raise_message_javascript(__('Error in Package'), __('The package "%s" download or validation failed', $package_name), __('See the cacti.log for more information. It could be that you had either an API Key error or the package was tamered with, or the location is not available.')); } } import_display_package_data($templates, $files, $package_name, $filename, $data); } else { raise_message_javascript(__('Error in Package'), __('The package download or validation failed'), __('See the cacti.log for more information. It could be that you had either an API Key error or the package was tamered with, or the location is not available')); } } function import_validate_public_key(string $xmlfile, bool $accept = false) : mixed { $public_key1 = get_public_key_sha1(); $public_key2 = get_public_key_sha256(); $info = import_get_package_info($xmlfile); if ($info !== false) { if ($info['pubkey'] != '') { // A weak key is never stored, and one stored before the floor // existed is no longer reported as accepted. This also keeps the // legacy 512-bit Cacti key out of the comparison below. if (!import_public_key_meets_minimum($info['pubkey'])) { return false; } $insert = false; $accepted = db_fetch_cell_prepared('SELECT COUNT(*) FROM package_public_keys WHERE public_key = ?', [$info['pubkey']]); if ($accepted) { return $info['pubkey']; } if ($public_key1 == $info['pubkey']) { $insert = true; } elseif ($public_key2 == $info['pubkey']) { $insert = true; } elseif ($accept) { $insert = true; } if ($insert) { db_execute_prepared('INSERT IGNORE INTO package_public_keys (md5sum, author, homepage, email_address, public_key) VALUES(?, ?, ?, ?, ?)', [md5($info['pubkey']), $info['author'], $info['homepage'], $info['email'], $info['pubkey']]); return $info['pubkey']; } } else { raise_message_javascript(__('Error in Package'), __('Package XML File Damaged.'), __('The XML files appears to be invalid and does not contain a public key. Please contact the package author to obtain a revised package.')); } } else { raise_message_javascript(__('Error in Package'), __('The XML files for the package does not exist'), __('Check the package repository file for files that should exist and find the one that is missing')); } return false; } function import_display_package_data(array $templates, array $files, string $package_name, string $filename, array $data, bool $multipackage = true) : void { global $device_classes; if (!$multipackage) { $details = import_package_get_details($filename); html_start_box(__('Packages Details'), '100%', false, 3, 'center', ''); $display_text = [ [ 'display' => __('Device Class') ], [ 'display' => __('Version'), ], [ 'display' => __('Copyright') ], [ 'display' => __('Author'), ], [ 'display' => __('Email') ], [ 'display' => __('Homepage'), ], ]; html_header($display_text); $id = 99; form_alternate_row('line_' . $id); if (isset($details['class']) && array_key_exists($details['class'], $device_classes)) { form_selectable_cell($device_classes[$details['class']], $id); } else { form_selectable_cell(__('Unknown'), $id); } form_selectable_ecell($details['version'], $id, '', 'center'); form_selectable_ecell($details['copyright'], $id); form_selectable_ecell($details['author'], $id); form_selectable_ecell($details['email'], $id); form_selectable_cell($details['homepage'], $id); form_end_row(); html_end_box(); } // Show the filename status' if (cacti_sizeof($files)) { html_start_box(__('Import Package Filenames [ None selected imports all, Check to import selectively ]'), '100%', false, 3, 'center', ''); $display_text = [ [ 'display' => __('Package'), ], [ 'display' => __('Filename'), ], [ 'display' => __('Status') ] ]; html_header_checkbox($display_text, false, '', true, 'file'); foreach ($files as $pdata => $pfiles) { [$file_package_file, $file_package_name] = explode('|', $pdata); foreach ($pfiles as $pfile => $status) { $id = 'file_' . base64_encode( json_encode( [ 'package' => $file_package_name, 'filename' => $file_package_file, 'pfile' => $pfile, ] ) ); form_alternate_row('line_' . $id); form_selectable_ecell($file_package_name, $id); form_selectable_ecell($pfile, $id); $status = explode(',', $status); $nstatus = ''; foreach ($status as $s) { $s = trim($s); if ($s == 'differences') { $url = 'package_import.php' . '?action=diff' . '&package_location=' . grv('package_location') . '&package_file=' . $file_package_file . '&package_name=' . $file_package_name . '&filename=' . str_replace(CACTI_PATH_BASE . '/', '', $pfile); $nstatus .= ($nstatus != '' ? ', ' : '') . "" . __('Differences') . ''; } elseif ($s == 'identical') { $nstatus .= ($nstatus != '' ? ', ' : '') . __('Unchanged'); } elseif ($s == 'not writable') { $nstatus .= ($nstatus != '' ? ', ' : '') . __('Not Writable'); } elseif ($s == 'writable') { $nstatus .= ($nstatus != '' ? ', ' : '') . __('Writable'); } elseif ($s == 'new') { $nstatus .= ($nstatus != '' ? ', ' : '') . __('New'); } else { $nstatus .= ($nstatus != '' ? ', ' : '') . __('Unknown'); } } form_selectable_cell($nstatus, $id); form_checkbox_cell($pfile, $id); form_end_row(); } } html_end_box(); } if (cacti_sizeof($templates)) { html_start_box(__('Import Package Templates [ None selected imports all, Check to import selectively ]'), '100%', false, 3, 'center', ''); if ($multipackage) { $display_text = [ [ 'display' => __('Packages'), ], [ 'display' => __('Template Type') ], [ 'display' => __('Template Name') ], [ 'display' => __('Status') ], [ 'display' => __('Changes/Diffferences') ] ]; } else { $display_text = [ [ 'display' => __('Template Type') ], [ 'display' => __('Template Name') ], [ 'display' => __('Status') ], [ 'display' => __('Changes/Diffferences') ] ]; } html_header_checkbox($display_text, false, '', true, 'import'); $templates = array_reverse($templates); foreach ($templates as $hash => $detail) { $files = explode('
    ', $detail['package_file']); $id = 'import_' . base64_encode( json_encode( [ 'package' => $detail['package'], 'hash' => $hash, 'type' => $detail['type_name'], 'name' => $detail['name'], 'status' => $detail['status'], 'files' => $files ] ) ); if ($detail['status'] == 'updated') { $status = "" . __('Updated') . ''; } elseif ($detail['status'] == 'new') { $status = "" . __('New') . ''; } else { $status = "" . __('Unchanged') . ''; } form_alternate_row('line_' . $id); if ($multipackage) { form_selectable_ecell($detail['package'], $id); } form_selectable_ecell($detail['type_name'], $id); form_selectable_ecell($detail['name'], $id); form_selectable_cell($status, $id); if (isset($detail['vals'])) { $diff_details = ''; $diff_array = []; $orphan_array = []; foreach ($detail['vals'] as $package => $diffs) { if (isset($diffs['differences'])) { foreach ($diffs['differences'] as $item) { $diff_array[$item] = $item; } } if (isset($diffs['orphans'])) { foreach ($diffs['orphans'] as $item) { $orphan_array[$item] = $item; } } } if (cacti_sizeof($diff_array)) { $diff_details .= __('Differences') . '
    ' . implode('
    ', $diff_array); } if (cacti_sizeof($orphan_array)) { $diff_details .= ($diff_details != '' ? '
    ' : '') . __('Orphans') . '
    ' . implode('
    ', $orphan_array); } form_selectable_cell($diff_details, $id, '', 'white-space:pre-wrap'); } else { form_selectable_cell(__('None'), $id); } form_checkbox_cell($detail['name'], $id); form_end_row(); } html_end_box(); } ?>
    '; } function get_repo_file(string $repo_id, string $filename = 'package.manifest', bool $javascript = false) : mixed { $repo = db_fetch_row_prepared('SELECT * FROM package_repositories WHERE id = ?', [$repo_id]); if (cacti_sizeof($repo)) { if ($repo['repo_type'] == 0) { // GitHub $repoloc = str_replace('github.com', 'raw.githubusercontent.com', $repo['repo_location']); $file = $repoloc . '/' . $repo['repo_branch'] . '/' . $filename; if ($repo['repo_api_key'] != '') { $options = [ 'https' => [ 'method' => 'GET', 'header' => 'Authorization: Bearer ' . $repo['repo_api_key'] ] ]; $context = stream_context_create($options); } else { $options = [ 'https' => [ 'method' => 'GET', ] ]; $context = stream_context_create($options); } $data = file_get_contents($file, false, $context); if ($data != '') { return $data; } if (!$javascript) { raise_message('repo_missing', __esc('The Repo \'%s\' is NOT Reachable on GitHub or the \'%s\' file is missing or it could be an invalid branch. Valid Package Locations are normally: https://github.com/Author/RepoName/.', $repo['name'], $filename), MESSAGE_LEVEL_ERROR); } } elseif ($repo['repo_type'] == 2) { // Direct URL $file = $repo['repo_location'] . '/' . $filename; $context = [ 'ssl' => [ 'verify_peer' => true, 'verify_peer_name' => true, ], ]; $data = file_get_contents($file, false, stream_context_create($context)); if ($data != '') { return $data; } if (!$javascript) { raise_message('repo_missing', __esc('The Repo \'%s\' is NOT Reachable at the URL Location or the package.manifest file is missing.', $repo['name']), MESSAGE_LEVEL_ERROR); } } else { // Server Directory $file = $repo['repo_location'] . '/' . $filename; if (file_exists($file)) { $data = file_get_contents($file); if ($data != '') { return $data; } if (!$javascript) { raise_message('repo_exists', __esc('The Repo \'%s\' is Reachable on the Local Cacti Server. But not data returned from the manifest file.', $repo['name']), MESSAGE_LEVEL_ERROR); } } elseif (!$javascript) { raise_message('repo_missing', __esc('The Repo \'%s\' is NOT Reachable on the Local Cacti Server or the package.manifest file is missing.', $repo['name']), MESSAGE_LEVEL_ERROR); } } } return false; } function get_repo_manifest_file(string $repo_id) : string { return get_repo_file($repo_id, 'package.manifest'); } function is_tmp_writable() : bool { $tmp_dir = sys_get_temp_dir(); $tmp_len = strlen($tmp_dir); $tmp_dir .= ($tmp_len !== 0 && substr($tmp_dir, -$tmp_len) === '/') ? '' : '/'; $is_tmp = is_resource_writable($tmp_dir); return $is_tmp; } function package_prepare_import_array(array &$templates, array &$files, string $package_name, string $package_filename, array $import_info) : void { global $hash_type_names; /** * This function will create an array of item types and their status * the user will have an option to import select items based upon * these values. * * $templates['template_hash'] = array( * 'package' => 'some_package_name', * 'package_file' => 'some_package_filename', * 'type' => 'some_type', * 'type_name' => 'some_type_name', * 'name' => 'some_name', * 'status' => 'some_status' * ); * * $files[$package_filename|$package_name] = array( * 'filename' => 'somefilename' * ); */ if (cacti_sizeof($import_info)) { if (cacti_sizeof($import_info[1])) { foreach ($import_info[1] as $filename => $status) { $files["$package_filename|$package_name"][$filename] = $status; } } foreach ($import_info[0] as $type => $type_array) { if ($type == 'files') { continue; } foreach ($type_array as $index => $vals) { $hash = $vals['hash']; if (!isset($templates[$hash])) { $templates[$hash]['package'] = $package_name; $templates[$hash]['package_file'] = $package_filename; $templates[$hash]['status'] = $vals['type']; } else { $templates[$hash]['package'] .= '
    ' . $package_name; $templates[$hash]['package_file'] .= '
    ' . $package_filename; $templates[$hash]['status'] .= '
    ' . $vals['type']; } $templates[$hash]['type'] = $type; $templates[$hash]['type_name'] = $hash_type_names[$type]; $templates[$hash]['name'] = $vals['title']; unset($vals['title']); unset($vals['result']); unset($vals['hash']); unset($vals['type']); if (isset($vals['dep'])) { unset($vals['dep']); } if (cacti_sizeof($vals)) { $templates[$hash]['vals'][$package_name] = $vals; } } } } }