mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-24 12:07:31 +09:00
* hardening(import): require a 2048-bit RSA key for Package signatures Apply the 1.2.x key floor from #7194 to every Package verify and every key develop trusts or stores, and stop trusting the legacy 512-bit Cacti key. Refs #8460 Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(changelog): add fragment for #8464 Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2133 lines
59 KiB
PHP
2133 lines
59 KiB
PHP
<?php
|
|
/*
|
|
+-------------------------------------------------------------------------+
|
|
| Copyright (C) 2004-2026 The Cacti Group |
|
|
| |
|
|
| This program is free software; you can redistribute it and/or |
|
|
| modify it under the terms of the GNU General Public License |
|
|
| as published by the Free Software Foundation; either version 2 |
|
|
| of the License, or (at your option) any later version. |
|
|
| |
|
|
| This program is distributed in the hope that it will be useful, |
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
| GNU General Public License for more details. |
|
|
+-------------------------------------------------------------------------+
|
|
| Cacti: The Complete RRDtool-based Graphing Solution |
|
|
+-------------------------------------------------------------------------+
|
|
| This code is designed, written, and maintained by the Cacti Group. See |
|
|
| about.php and/or the AUTHORS file for specific developer information. |
|
|
+-------------------------------------------------------------------------+
|
|
| http://www.cacti.net/ |
|
|
+-------------------------------------------------------------------------+
|
|
*/
|
|
|
|
require('./include/auth.php');
|
|
require_once(CACTI_PATH_LIBRARY . '/import.php');
|
|
require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
|
require_once(CACTI_PATH_LIBRARY . '/template.php');
|
|
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
|
require_once(CACTI_PATH_LIBRARY . '/xml.php');
|
|
|
|
use Jfcherng\Diff\Differ;
|
|
use Jfcherng\Diff\Factory\RendererFactory;
|
|
|
|
// set default action
|
|
set_default_action();
|
|
|
|
check_tmp_dir();
|
|
|
|
$actions = [
|
|
1 => __('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 {
|
|
?>
|
|
<script type='text/javascript'>
|
|
var mixedReasonTitle = '<?php print __('Key Generation Required to Use Tool'); ?>';
|
|
var mixedOnPage = '<?php print __esc('Packaging Key Information Not Found'); ?>';
|
|
|
|
sessionMessage = {
|
|
message: '<?php print __('In order to use this Packaging Tool, you must first run the <b><i class="deviceUp">genkey.php</i></b> script in the cli directory. Once that is complete, you will have a public and private key used to sign your packages.'); ?>',
|
|
level: MESSAGE_LEVEL_MIXED
|
|
};
|
|
|
|
$(function() {
|
|
displayMessages();
|
|
});
|
|
</script>
|
|
<?php
|
|
|
|
exit;
|
|
}
|
|
}
|
|
|
|
function form_actions() : void {
|
|
global $actions;
|
|
|
|
// ================= input validation =================
|
|
gfrv('drp_action', FILTER_VALIDATE_REGEXP, ['options' => ['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 .= '<tr>' .
|
|
'<td style="width:50%">' . htmle($id['package']) . '</td>' .
|
|
'<td style="width:50%">' . htmle($id['pfile']) . '</td>' .
|
|
'</td>';
|
|
|
|
$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('<br>', $id['package']);
|
|
$package = '';
|
|
|
|
foreach ($packages as $index => $p) {
|
|
$package .= ($index > 0 ? ', ' : '') . htmle($p);
|
|
|
|
$found_pkg_array[$p] = $p;
|
|
}
|
|
|
|
$statuses = explode('<br>', $id['status']);
|
|
$status = '';
|
|
|
|
foreach ($statuses as $index => $s) {
|
|
$status .= ($index > 0 ? ', ' : '') . htmle(ucfirst($s));
|
|
}
|
|
|
|
$pkg_import_list .= '<tr>' .
|
|
'<td style="width:40%">' . $package . '</td>' .
|
|
'<td style="width:20%">' . htmle($id['type']) . '</td>' .
|
|
'<td style="width:20%">' . htmle($id['name']) . '</td>' .
|
|
'<td style="width:20%">' . $status . '</td>' .
|
|
'</td>';
|
|
|
|
$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 .= '<li>' . htmle($package) . '</li>';
|
|
$pkg_array[] = $matches[1];
|
|
} else {
|
|
$skp_list .= '<li>' . htmle($package) . '</li>';
|
|
$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 "<tr>
|
|
<td class='textArea'>
|
|
<p>" . __n('Click \'Continue\' to Import the following Package.', 'Click \'Continue\' to Import all following Packages.', cacti_sizeof($pkg_array)) . "</p>
|
|
<div class='itemlist'><ul>$pkg_list</ul></div>
|
|
</td>
|
|
</tr>";
|
|
|
|
if ($skp_list != '') {
|
|
print "<tr>
|
|
<td class='textArea'>
|
|
<p>" . __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)) . "</p>
|
|
<div class='itemlist'><ul>$skp_list</ul></div>
|
|
</td>
|
|
</tr>";
|
|
}
|
|
|
|
if ($pkg_file_list != '') {
|
|
print '<tr><td><div class="cactiTableTitleRow">' . __('Files to be Imported') . '</div></td></tr>';
|
|
|
|
print "<tr>
|
|
<td class='textArea'>
|
|
<p>" . __('The Files in the list below will be imported.') . "</p>
|
|
<table class='cactiTable itemlist'>
|
|
<tr class='tableHeader'>
|
|
<th>" . __('Package') . '</th>
|
|
<th>' . __('File') . "</th>
|
|
</tr>
|
|
$pkg_file_list
|
|
</table>
|
|
</td>
|
|
</tr>";
|
|
}
|
|
|
|
if ($pkg_import_list != '') {
|
|
print '<tr><td><div class="cactiTableTitleRow">' . __('Template Items to be Imported') . '</div></td></tr>';
|
|
|
|
print "<tr>
|
|
<td class='textArea'>
|
|
<p>" . __('The Template Items in the list below will be imported.') . "</p>
|
|
<table class='cactiTable itemlist'>
|
|
<tr class='tableHeader'>
|
|
<th>" . __('Package') . '</th>
|
|
<th>' . __('Type') . '</th>
|
|
<th>' . __('Name') . '</th>
|
|
<th>' . __('Status') . "</th>
|
|
</tr>
|
|
$pkg_import_list
|
|
</table>
|
|
</td>
|
|
</tr>";
|
|
}
|
|
|
|
$save_html = "<button type='button' class='ui-button ui-corner-all ui-widget' onClick='cactiReturnTo()'>" . __esc('Cancel') . "</button><button type='submit' class='ui-button ui-corner-all ui-widget ui-state-active' title='" . __n('Import Package', 'Import Packages', cacti_sizeof($pkg_array)) . "'>" . __esc('Continue') . '</button>';
|
|
} 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 "<tr>
|
|
<td class='saveRow'>
|
|
" . html_hidden_input('action', 'actions') . '
|
|
' . html_hidden_input('import_state', $import_state) . '
|
|
' . html_hidden_input('drp_action', grv('drp_action')) . "
|
|
$save_html
|
|
</td>
|
|
</tr>";
|
|
|
|
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 <ins>/<del> markup.
|
|
print '<body>' . $renderer->render($differ) . '</body></html>'; // 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.<br>');
|
|
$authors = [];
|
|
$packages = [];
|
|
|
|
foreach ($failed as $package) {
|
|
$packages[] = $package['name'];
|
|
|
|
$authors[$package['author']] = $package['email'];
|
|
}
|
|
|
|
foreach ($authors as $author => $email) {
|
|
$message .= ($message != '' ? '<br>' : '') . __('<b>Author:</b> <%s> %s.<br>', htmle($author), htmle($email));
|
|
}
|
|
|
|
foreach ($packages as $package) {
|
|
$message .= ($message != '' ? '<br>' : '') . __('<b>Package:</b> %s', htmle($package));
|
|
}
|
|
|
|
$message .= '<br><br>' . __('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 != '' ? ', ' : '') .
|
|
"<a class='diffme linkEditMain' href='" . htmle($url) . "'>" . __('Differences') . '</a>';
|
|
} 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('<br>', $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 = "<span class='updateObject'>" . __('Updated') . '</span>';
|
|
} elseif ($detail['status'] == 'new') {
|
|
$status = "<span class='newObject'>" . __('New') . '</span>';
|
|
} else {
|
|
$status = "<span class='deviceUp'>" . __('Unchanged') . '</span>';
|
|
}
|
|
|
|
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') . '<br>' . implode('<br>', $diff_array);
|
|
}
|
|
|
|
if (cacti_sizeof($orphan_array)) {
|
|
$diff_details .= ($diff_details != '' ? '<br>' : '') . __('Orphans') . '<br>' . implode('<br>', $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();
|
|
}
|
|
|
|
?>
|
|
<script type='text/javascript'>
|
|
|
|
function getURLVariable(url, varname) {
|
|
var urlparts = url.slice(url.indexOf('?') + 1).split('&');
|
|
|
|
for (var i = 0; i < urlparts.length; i++) {
|
|
var urlvar = urlparts[i].split('=');
|
|
|
|
if (urlvar[0] == varname) {
|
|
return urlvar[1];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
$(function() {
|
|
if ($('#package_import_details2_child').length) {
|
|
applySelectorVisibilityAndActions();
|
|
|
|
$('#package_import_details2_child').find('tr[id^="line_import_new_"]').each(function(event) {
|
|
selectUpdateRow(event, $(this));
|
|
});
|
|
|
|
makePackagesClickable();
|
|
}
|
|
|
|
$('.diffme').rebind('click', function(event) {
|
|
event.preventDefault();
|
|
|
|
var url = $(this).attr('href');
|
|
|
|
$.get(url, function(data) {
|
|
$('#dialog').html(data);
|
|
|
|
var package_name = getURLVariable(url, 'package_name');
|
|
var filename = getURLVariable(url, 'filename');
|
|
|
|
$('#dialog').dialog({
|
|
autoOpen: true,
|
|
title: '<?php print __('File Differences for: '); ?>' + filename,
|
|
width: '60%',
|
|
maxWidth: '90%',
|
|
maxHeight: 600
|
|
});
|
|
});
|
|
});
|
|
});
|
|
<?php
|
|
}
|
|
|
|
function validate_request_vars() : void {
|
|
$default_profile = get_default_profile();
|
|
|
|
// ================= input validation and session storage =================
|
|
$filters = [
|
|
'replace_svalues' => [
|
|
'filter' => FILTER_VALIDATE_REGEXP,
|
|
'options' => ['options' => ['regexp' => '(on|true|false)']],
|
|
'default' => read_config_option('replace_svalues') ?? ''
|
|
],
|
|
'remove_orphans' => [
|
|
'filter' => FILTER_VALIDATE_REGEXP,
|
|
'options' => ['options' => ['regexp' => '(on|true|false)']],
|
|
'default' => read_config_option('remove_orphans') ?? ''
|
|
],
|
|
'package_location' => [
|
|
'filter' => FILTER_VALIDATE_INT,
|
|
'default' => read_config_option('package_location') ?? ''
|
|
],
|
|
'data_source_profile' => [
|
|
'filter' => FILTER_VALIDATE_INT,
|
|
'default' => $default_profile
|
|
],
|
|
'image_format' => [
|
|
'filter' => FILTER_VALIDATE_INT,
|
|
'default' => read_config_option('default_image_format') ?? 'SVG'
|
|
],
|
|
'graph_width' => [
|
|
'filter' => FILTER_VALIDATE_INT,
|
|
'default' => read_config_option('default_graph_width') ?? '700'
|
|
],
|
|
'graph_height' => [
|
|
'filter' => FILTER_VALIDATE_INT,
|
|
'default' => read_config_option('default_graph_height') ?? '200'
|
|
],
|
|
];
|
|
|
|
validate_store_request_vars($filters, 'sess_pimport');
|
|
// ================= input validation =================
|
|
}
|
|
|
|
function get_import_form(int $repo_id, int $default_profile) : array {
|
|
global $image_types;
|
|
|
|
validate_request_vars();
|
|
|
|
if (isrv('preview_only') && gnrv('preview_only') == 'on') {
|
|
$preview_only = 'on';
|
|
} else {
|
|
$preview_only = '';
|
|
}
|
|
|
|
if (isrv('replace_svalues') && gnrv('replace_svalues') == 'on') {
|
|
$replace_svalues = 'on';
|
|
} else {
|
|
$replace_svalues = '';
|
|
}
|
|
|
|
if (isrv('remove_orphans') && gnrv('remove_orphans') == 'on') {
|
|
$remove_orphans = 'on';
|
|
} else {
|
|
$remove_orphans = '';
|
|
}
|
|
|
|
if (isrv('image_format')) {
|
|
$image_format = gfrv('image_format');
|
|
} else {
|
|
$image_format = read_config_option('default_image_format');
|
|
}
|
|
|
|
if (isrv('graph_width')) {
|
|
$graph_width = gfrv('graph_width');
|
|
} else {
|
|
$graph_width = read_config_option('default_graph_width');
|
|
}
|
|
|
|
if (isrv('graph_height')) {
|
|
$graph_height = gfrv('graph_height');
|
|
} else {
|
|
$graph_height = read_config_option('default_graph_height');
|
|
}
|
|
|
|
$form = [
|
|
'import_file' => [
|
|
'friendly_name' => __('Local Package Import File'),
|
|
'description' => __('The *.xml.gz file located on your Local machine to Upload and Import.'),
|
|
'accept' => '.xml.gz',
|
|
'method' => 'file'
|
|
],
|
|
];
|
|
|
|
$form2 = [
|
|
'data_header' => [
|
|
'friendly_name' => __('Data Source Overrides'),
|
|
'collapsible' => 'true',
|
|
'method' => 'spacer',
|
|
],
|
|
'data_source_profile' => [
|
|
'friendly_name' => __('Data Source Profile'),
|
|
'description' => __('Select the Data Source Profile. The Data Source Profile controls polling interval, the data aggregation, and retention policy for the resulting Data Sources.'),
|
|
'method' => 'drop_sql',
|
|
'sql' => 'SELECT id, name FROM data_source_profiles ORDER BY name',
|
|
'none_value' => __('Create New from Template'),
|
|
'value' => isrv('import_dsp') ? gfrv('import_dsp') : '',
|
|
'default' => $default_profile
|
|
],
|
|
'graph_header' => [
|
|
'friendly_name' => __('Graph/Data Template Overrides'),
|
|
'collapsible' => 'true',
|
|
'method' => 'spacer',
|
|
],
|
|
'remove_orphans' => [
|
|
'friendly_name' => __('Remove Orphaned Graph Items'),
|
|
'description' => __('If checked, Cacti will delete any Graph Items from both the Graph Template and associated Graphs that are not included in the imported Graph Template.'),
|
|
'method' => 'checkbox',
|
|
'value' => $remove_orphans,
|
|
'default' => ''
|
|
],
|
|
'replace_svalues' => [
|
|
'friendly_name' => __('Replace Suggested Value Patterns'),
|
|
'description' => __('Replace Data Source and Graph Template Suggested Value Records. Graphs and Data Sources will take on new names after either a Data Query Reindex or by using the forced Replace Suggested Values process.'),
|
|
'method' => 'checkbox',
|
|
'value' => $replace_svalues,
|
|
'default' => ''
|
|
],
|
|
'image_format' => [
|
|
'friendly_name' => __('Graph Template Image Format'),
|
|
'description' => __('The Image Format to be used when importing or updating Graph Templates.'),
|
|
'method' => 'drop_array',
|
|
'default' => read_config_option('default_image_format'),
|
|
'value' => $image_format,
|
|
'array' => $image_types,
|
|
],
|
|
'graph_height' => [
|
|
'friendly_name' => __('Graph Template Height', 'pagkage'),
|
|
'description' => __('The Height to be used when importing or updating Graph Templates.'),
|
|
'method' => 'textbox',
|
|
'default' => read_config_option('default_graph_height'),
|
|
'size' => '5',
|
|
'value' => $graph_height,
|
|
'max_length' => '5'
|
|
],
|
|
'graph_width' => [
|
|
'friendly_name' => __('Graph Template Width'),
|
|
'description' => __('The Width to be used when importing or updating Graph Templates.'),
|
|
'method' => 'textbox',
|
|
'default' => read_config_option('default_graph_width'),
|
|
'size' => '5',
|
|
'value' => $graph_width,
|
|
'max_length' => '5'
|
|
]
|
|
];
|
|
|
|
if ($repo_id == 0) {
|
|
return array_merge($form, $form2);
|
|
} else {
|
|
return $form2;
|
|
}
|
|
}
|
|
|
|
function get_default_profile() : mixed {
|
|
$default_profile = db_fetch_cell('SELECT id
|
|
FROM data_source_profiles
|
|
WHERE `default`="on"');
|
|
|
|
if (empty($default_profile)) {
|
|
$default_profile = db_fetch_cell('SELECT id
|
|
FROM data_source_profiles
|
|
ORDER BY id
|
|
LIMIT 1');
|
|
}
|
|
|
|
return $default_profile;
|
|
}
|
|
|
|
function package_import() : void {
|
|
global $actions, $hash_type_names, $device_classes;
|
|
|
|
validate_request_vars();
|
|
|
|
$display_hideme = false;
|
|
|
|
$default = db_fetch_cell('SELECT id
|
|
FROM package_repositories
|
|
WHERE `default` = "on"');
|
|
|
|
if (!isrv('package_location')) {
|
|
srv('package_location', $default);
|
|
}
|
|
|
|
if (!isrv('package_class')) {
|
|
srv('package_class', '0');
|
|
}
|
|
|
|
$device_classes = array_merge([0 => __('All')], $device_classes);
|
|
|
|
if (grv('package_location') == 0) {
|
|
form_start('package_import.php', 'import', true);
|
|
} else {
|
|
form_start('package_import.php', 'import');
|
|
}
|
|
|
|
$repos = array_rekey(
|
|
db_fetch_assoc('SELECT id, name
|
|
FROM package_repositories
|
|
WHERE enabled = "on"
|
|
ORDER BY name'),
|
|
'id', 'name'
|
|
);
|
|
|
|
$repos[0] = __('Local Package File');
|
|
|
|
$pform = [
|
|
'package_location' => [
|
|
'friendly_name' => __('Package Location'),
|
|
'description' => __('Select the Location of the Packages that you wish to Import.'),
|
|
'method' => 'drop_array',
|
|
'value' => isrv('package_location') ? gfrv('package_location') : $default,
|
|
'array' => $repos,
|
|
'default' => $default
|
|
]
|
|
];
|
|
|
|
$package_location = intval(grv('package_location'));
|
|
|
|
$default_profile = db_fetch_cell('SELECT id
|
|
FROM data_source_profiles
|
|
WHERE `default`="on"');
|
|
|
|
if (empty($default_profile)) {
|
|
$default_profile = db_fetch_cell('SELECT id
|
|
FROM data_source_profiles
|
|
ORDER BY id
|
|
LIMIT 1');
|
|
}
|
|
|
|
$form = get_import_form($package_location, $default_profile);
|
|
|
|
if (isrv('package_location') && gnrv('package_location') == 0) {
|
|
html_start_box(__('Package Import'), '100%', false, 3, 'center', '');
|
|
|
|
draw_edit_form(
|
|
[
|
|
'config' => ['no_form_tag' => true],
|
|
'fields' => $pform
|
|
]
|
|
);
|
|
|
|
html_end_box();
|
|
|
|
html_start_box(__('Local Package Import'), '100%', true, 3, 'center', '');
|
|
|
|
draw_edit_form(
|
|
[
|
|
'config' => ['no_form_tag' => true],
|
|
'fields' => $form
|
|
]
|
|
);
|
|
|
|
html_end_box(true, true);
|
|
|
|
form_hidden_box('save_component_import', '1', '');
|
|
form_hidden_box('import_confirmed', '', '');
|
|
|
|
form_save_button('', 'import', 'import', false);
|
|
|
|
print "<div id='contents'></div>";
|
|
|
|
form_dialog_box();
|
|
} else {
|
|
html_start_box(__('Package Import'), '100%', false, 3, 'center', '');
|
|
|
|
draw_edit_form(
|
|
[
|
|
'config' => ['no_form_tag' => true],
|
|
'fields' => $pform
|
|
]
|
|
);
|
|
|
|
html_end_box();
|
|
|
|
html_start_box(__('Package Import Preferences'), '100%', true, 3, 'center', '');
|
|
|
|
draw_edit_form(
|
|
[
|
|
'config' => ['no_form_tag' => true],
|
|
'fields' => $form
|
|
]
|
|
);
|
|
|
|
html_end_box(true, true);
|
|
|
|
html_start_box(__('Repository Based Package Import'), '100%', false, 3, 'center', '');
|
|
|
|
$display_text = [
|
|
'name' => [
|
|
'display' => __('Name'),
|
|
],
|
|
'class' => [
|
|
'display' => __('Class'),
|
|
],
|
|
'version' => [
|
|
'display' => __('Version'),
|
|
],
|
|
'copyright' => [
|
|
'display' => __('Copyright'),
|
|
],
|
|
'author' => [
|
|
'display' => __('Author'),
|
|
],
|
|
'email' => [
|
|
'display' => __('Email'),
|
|
],
|
|
];
|
|
|
|
unset($repos[0]);
|
|
|
|
html_header_checkbox($display_text, false, '', true);
|
|
|
|
$id = gfrv('package_location');
|
|
|
|
$repo = json_decode(get_repo_manifest_file($id), true);
|
|
|
|
$i = 0;
|
|
|
|
if (cacti_sizeof($repo)) {
|
|
$repos = $repo['manifest'];
|
|
|
|
foreach ($repos as $repo) {
|
|
$subid = 'package_' . $i;
|
|
|
|
form_alternate_row('line_' . $subid, true);
|
|
|
|
if (!isset($repo['metadata']['copyright'])) {
|
|
$copyright = __('Not Set');
|
|
} else {
|
|
$copyright = $repo['metadata']['copyright'];
|
|
}
|
|
|
|
if (isset($repo['metadata']['class']) && isset($device_classes[$repo['metadata']['class']])) {
|
|
$class = $device_classes[$repo['metadata']['class']];
|
|
} else {
|
|
$class = __('Unknown');
|
|
}
|
|
|
|
form_selectable_ecell($repo['name'], $subid);
|
|
form_selectable_ecell($class, $subid);
|
|
form_selectable_ecell($repo['metadata']['version'], $subid);
|
|
form_selectable_ecell($copyright, $subid);
|
|
form_selectable_ecell($repo['metadata']['author'], $subid);
|
|
form_selectable_ecell($repo['metadata']['email'], $subid);
|
|
|
|
form_checkbox_cell($repo['name'], $subid);
|
|
|
|
form_end_row();
|
|
|
|
$i++;
|
|
}
|
|
} else {
|
|
print "<tr class='tableRow odd'><td colspan='" . (cacti_sizeof($display_text) + 1) . "'><em>" . __('No Packages Found') . '</em></td></tr>';
|
|
}
|
|
|
|
html_end_box(true);
|
|
|
|
form_hidden_box('save_component_import', '1', '');
|
|
form_hidden_box('import_confirmed', '', '');
|
|
|
|
draw_actions_dropdown($actions);
|
|
}
|
|
|
|
?>
|
|
<div id='contents'></div>
|
|
<div id='dialog'></div>
|
|
|
|
<script type='text/javascript'>
|
|
function switchRepo() {
|
|
var package_location = $('#package_location').val();
|
|
var remove_orphans = $('#remove_orphans').is(':checked');
|
|
var replace_svalues = $('#replace_svalues').is(':checked');
|
|
var data_source_profile = $('#data_source_profile').val();
|
|
var package_class = $('#package_class').val();
|
|
var image_format = $('#image_format').val();
|
|
var graph_width = $('#graph_width').val();
|
|
var graph_height = $('#graph_height').val();
|
|
|
|
var strURL = urlPath + 'package_import.php' +
|
|
'?package_location=' + package_location +
|
|
'&remove_orphans=' + remove_orphans +
|
|
'&replace_svalues=' + replace_svalues +
|
|
'&import_dsp=' + data_source_profile +
|
|
'&image_format=' + image_format +
|
|
'&graph_height=' + graph_height +
|
|
'&graph_width=' + graph_width;
|
|
|
|
loadUrl({ url: strURL });
|
|
}
|
|
|
|
function packagesChanged() {
|
|
var checks = ''
|
|
|
|
$('input[id^="chk_package"]:checked').each(function() {
|
|
checks += (checks != '' ? ',':'') + $(this).attr('id').replace('chk_package_', '');
|
|
});
|
|
|
|
if (checks != '') {
|
|
$.get('package_import.php?action=details' +
|
|
'&package_location=' + $('#package_location').val() +
|
|
'&data_source_profile=' + $('#data_source_profile').val() +
|
|
'&image_format=' + $('#image_format').val() +
|
|
'&graph_height=' + $('#graph_height').val() +
|
|
'&graph_width=' + $('#graph_width').val() +
|
|
'&replace_svalues=' + $('#replace_svalues').is(':checked') +
|
|
'&remove_orphans=' + $('#remove_orphans').is(':checked') +
|
|
'&package_ids=' + checks, function(data) {
|
|
|
|
$('#contents').html(data);
|
|
});
|
|
} else {
|
|
$('#contents').empty();
|
|
}
|
|
}
|
|
|
|
function checkSigner() {
|
|
var checks = ''
|
|
|
|
$('input[id^="chk_package"]:checked').each(function() {
|
|
checks += (checks != '' ? ',':'') + $(this).attr('id').replace('chk_package_', '');
|
|
});
|
|
|
|
if (checks != '' || $('#package_location').val() == 0) {
|
|
$.getJSON('package_import.php?action=verify' +
|
|
'&package_location=' + $('#package_location').val() +
|
|
'&package_ids=' + checks, function(data) {
|
|
|
|
if (data.status == 'error') {
|
|
if ($('#import_dialog').length == 0) {
|
|
$('body').append('<div id="import_dialog"><div id="import_message"></div></div>');
|
|
}
|
|
|
|
$('#import_message').html(data.message);
|
|
$('#import_dialog').attr('title', data.title);
|
|
|
|
$('#import_dialog').dialog({
|
|
autoOpen: true,
|
|
width: '400px',
|
|
maxHeight: '400px',
|
|
modal: true,
|
|
buttons: {
|
|
Cancel: function() {
|
|
$(this).dialog('close');
|
|
},
|
|
Ok: function() {
|
|
$('#import_dialog').dialog('close');
|
|
trustSigner();
|
|
|
|
if ($('#package_location').val() != '0') {
|
|
packagesChanged();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
} else if (data.status == 'fileerror') {
|
|
var mixedReasonTitle = data.title;
|
|
var mixedOnPage = data.header;
|
|
sessionMessage = {
|
|
message: data.message,
|
|
level: MESSAGE_LEVEL_MIXED
|
|
};
|
|
|
|
displayMessages();
|
|
} else if ($('#package_location').val() != '0') {
|
|
packagesChanged();
|
|
}
|
|
});
|
|
} else if ($('#package_location').val() != '0') {
|
|
$('#contents').empty();
|
|
}
|
|
}
|
|
|
|
function trustSigner() {
|
|
var checks = ''
|
|
|
|
$('input[id^="chk_package"]:checked').each(function() {
|
|
checks += (checks != '' ? ',':'') + $(this).attr('id').replace('chk_package_', '');
|
|
});
|
|
|
|
if (checks != '' || $('#package_location').val() == 0) {
|
|
/* accept is state-changing (trusts a signer), so it must arrive by
|
|
* POST with a CSRF token like the other 'bad_actions' in global.php */
|
|
$.post('package_import.php?action=accept', {
|
|
package_location: $('#package_location').val(),
|
|
package_ids: checks,
|
|
__csrf_magic: csrfMagicToken
|
|
}, function(data) {
|
|
}, 'json');
|
|
}
|
|
}
|
|
|
|
function makePackagesClickable() {
|
|
$('#package_import3_child').find('tr[id^="line"]').on('click', function() {
|
|
if (checkSigner()) {
|
|
packagesChanged($(this));
|
|
}
|
|
});
|
|
}
|
|
|
|
$(function() {
|
|
refreshMSeconds = 9999999;
|
|
|
|
$('#package_location').rebind('change', function() {
|
|
switchRepo();
|
|
});
|
|
|
|
$('#import_file').rebind('change', function() {
|
|
var form = $('#import')[0];
|
|
var data = new FormData(form);
|
|
var formExtra = '?action=upload&package_location=0&preview_only=on';
|
|
|
|
if ($('#remove_orphans').is(':checked')) {
|
|
formExtra += '&remove_orphans=on';
|
|
} else {
|
|
formExtra += '&remove_orphans=';
|
|
}
|
|
|
|
if ($('#replace_svalues').is(':checked')) {
|
|
formExtra += '&replace_svalues=on';
|
|
} else {
|
|
formExtra += '&replace_svalues=';
|
|
}
|
|
|
|
Pace.start();
|
|
|
|
$.ajax({
|
|
type: 'POST',
|
|
enctype: 'multipart/form-data',
|
|
url: urlPath + 'package_import.php' + formExtra,
|
|
data: data,
|
|
processData: false,
|
|
contentType: false,
|
|
cache: false,
|
|
timeout: 10000,
|
|
success: function (data) {
|
|
if ($('#contents').length == 0) {
|
|
$('#main').append('<div id="contents"></div>');
|
|
} else {
|
|
$('#contents').empty();
|
|
}
|
|
|
|
$('#contents').html(data);
|
|
|
|
$('#import_confirmed').val('on');
|
|
|
|
Pace.stop();
|
|
|
|
checkSigner()
|
|
},
|
|
error: function (event) {
|
|
if ($('#contents').length == 0) {
|
|
$('#main').append('<div id="contents"></div>');
|
|
} else {
|
|
$('#contents').empty();
|
|
}
|
|
|
|
$('#contents').html(data);
|
|
|
|
Pace.stop();
|
|
}
|
|
});
|
|
});
|
|
|
|
makePackagesClickable();
|
|
|
|
$('#selectall').change(function() {
|
|
if (checkSigner()) {
|
|
packagesChanged();
|
|
}
|
|
});
|
|
|
|
$('.import_label').button();
|
|
$('.import_button').change(function() {
|
|
text=this.value;
|
|
setImportFile(text);
|
|
});
|
|
|
|
setImportFile(noFileSelected);
|
|
|
|
function setImportFile(fileText) {
|
|
$('.import_text').text(fileText);
|
|
}
|
|
});
|
|
</script>
|
|
<?php
|
|
|
|
form_end();
|
|
}
|
|
|
|
function form_dialog_box() : void {
|
|
print '<div style="display:none">
|
|
<div id="import_dialog" title="">
|
|
<div id="import_message"></div>
|
|
</div>
|
|
</div>';
|
|
}
|
|
|
|
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'] .= '<br>' . $package_name;
|
|
$templates[$hash]['package_file'] .= '<br>' . $package_filename;
|
|
$templates[$hash]['status'] .= '<br>' . $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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|