Add functionality to pull/sync assets & info from MeshCentral

This commit is contained in:
Marcus Hill 2022-02-26 21:51:37 +00:00
parent e16c5fe8ba
commit e4dc22a0ce
13 changed files with 3025 additions and 5 deletions

View File

@ -34,6 +34,7 @@ if(isset($_GET['client_id'])){
$client_net_terms = $config_default_net_terms;
}
$client_notes = $row['client_notes'];
$client_meshcentral_group = $row['client_meshcentral_group'];
$client_created_at = $row['client_created_at'];
$primary_contact = $row['primary_contact'];
$primary_location = $row['primary_location'];

View File

@ -44,7 +44,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Name the asset" value="<?php echo $asset_name; ?>" required>
<input type="text" class="form-control" name="name" placeholder="Name the asset" value="<?php echo $asset_name; ?>" <?php if(!empty($asset_meshcentral_id)){echo "disabled";} ?> required>
</div>
</div>
@ -102,7 +102,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fab fa-fw fa-windows"></i></span>
</div>
<input type="text" class="form-control" name="os" placeholder="ex Windows 10 Pro" value="<?php echo $asset_os; ?>">
<input type="text" class="form-control" name="os" placeholder="ex Windows 10 Pro" <?php if(!empty($asset_meshcentral_id)){echo "disabled";} ?> value="<?php echo $asset_os; ?>">
</div>
</div>
<?php } ?>
@ -206,6 +206,16 @@
<input type="text" class="form-control" name="mac" value="<?php echo $asset_mac; ?>" placeholder="MAC Address" data-inputmask="'alias': 'mac'" data-mask>
</div>
</div>
<div class="form-group">
<label>MeshCentral Node ID</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-sync"></i></span>
</div>
<input type="text" class="form-control" name="mesh_id" value="<?php echo $asset_meshcentral_id; ?>" placeholder="MeshCentral ID">
</div>
</div>
</div>
@ -296,7 +306,7 @@
<div class="tab-pane fade" id="pills-notes<?php echo $asset_id; ?>">
<div class="form-group">
<textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes"><?php echo $asset_notes; ?></textarea>
<textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes" <?php if(!empty($asset_meshcentral_id)){echo "disabled";} ?>><?php echo $asset_notes; ?></textarea>
</div>
</div>

View File

@ -98,6 +98,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()"));
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-desktop"></i> Assets</h3>
<div class="card-tools">
<?php if(!empty($client_meshcentral_group)) { ?><button type="button" class="btn btn-primary" onclick="window.open('plugins/meshctrl/mesh.php', '', '_blank,width=500,height=500')"><i class="fas fa-fw fa-sync"></i> Sync Assets</button><?php } ?>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addAssetModal"><i class="fas fa-fw fa-plus"></i> New <?php if(!empty($_GET['type'])){ echo ucwords($_GET['type']); }else{ echo "Asset"; } ?></button>
</div>
</div>
@ -210,6 +211,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()"));
$asset_ip_display = "$asset_ip<button class='btn btn-sm' data-clipboard-text='$asset_ip'><i class='far fa-copy text-secondary'></i></button>";
}
$asset_mac = $row['asset_mac'];
$asset_meshcentral_id = $row['asset_meshcentral_id'];
$asset_purchase_date = $row['asset_purchase_date'];
$asset_warranty_expire = $row['asset_warranty_expire'];
$asset_install_date = $row['asset_install_date'];

View File

@ -21,6 +21,9 @@
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-client-tag<?php echo $client_id; ?>">Tag</a>
</li>
<li class="nav-iem">
<a class="nav-link" data-toggle="pill" href="#pills-client-integration<?php echo $client_id; ?>">Integration</a>
</li>
</ul>
<hr>
@ -154,6 +157,20 @@
</ul>
</div>
<div class="tab-pane fade" id="pills-client-integration<?php echo $client_id; ?>">
<div class="form-group">
<label>MeshCentral Device Group Name</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-object-group"></i></span>
</div>
<input type="text" class="form-control" name="meshcentral_group" placeholder="CoolClient" value="<?php echo $client_meshcentral_group; ?>">
</div>
</div>
</div>
</div>
</div>

View File

@ -193,6 +193,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()"));
$client_net_terms = $row['client_net_terms'];
$client_referral = $row['client_referral'];
$client_notes = $row['client_notes'];
$client_meshcentral_group = $row['client_meshcentral_group'];
$client_created_at = $row['client_created_at'];
$client_updated_at = $row['client_updated_at'];

5
db.sql
View File

@ -77,6 +77,7 @@ CREATE TABLE `assets` (
`asset_install_date` date DEFAULT NULL,
`asset_reciept` varchar(200) DEFAULT NULL,
`asset_notes` text DEFAULT NULL,
`asset_meshcentral_id` varchar(200) NOT NULL,
`asset_created_at` datetime NOT NULL,
`asset_updated_at` datetime DEFAULT NULL,
`asset_archived_at` datetime DEFAULT NULL,
@ -238,6 +239,7 @@ CREATE TABLE `clients` (
`client_currency_code` varchar(200) NOT NULL,
`client_net_terms` int(10) NOT NULL,
`client_notes` text DEFAULT NULL,
`client_meshcentral_group` varchar(200) NOT NULL,
`client_created_at` datetime NOT NULL,
`client_updated_at` datetime DEFAULT NULL,
`client_archived_at` datetime DEFAULT NULL,
@ -1114,6 +1116,9 @@ CREATE TABLE `settings` (
`config_stripe_enable` tinyint(1) DEFAULT NULL,
`config_stripe_publishable` varchar(255) DEFAULT NULL,
`config_stripe_secret` varchar(255) DEFAULT NULL,
`config_meshcentral_uri` varchar(200) NOT NULL,
`config_meshcentral_user` varchar(200) NOT NULL,
`config_meshcentral_secret` varchar(200) NOT NULL,
PRIMARY KEY (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;

View File

@ -7,6 +7,11 @@ $row = mysqli_fetch_array($sql_settings);
// General
$config_base_url = $row['config_base_url'];
// Mesh Central
$config_meshcentral_uri = $row['config_meshcentral_uri'];
$config_meshcentral_user = $row['config_meshcentral_user'];
$config_meshcentral_secret = decryptLoginEntry($row['config_meshcentral_secret']);
// Mail
$config_smtp_host = $row['config_smtp_host'];
$config_smtp_port = $row['config_smtp_port'];

94
plugins/meshctrl/mesh.php Normal file
View File

@ -0,0 +1,94 @@
<?php
/*
* mesh_asset_sync.php
* Wrapper around meshctrl.js to pull device data from Mesh Central
* meshctrl.js is written in Node and requires npm packages minimist & ws
*/
// Includes
include("../../config.php");
include("../../functions.php");
include("../../check_login.php");
// Login token
$url = escapeshellarg($config_meshcentral_uri);
$usr = escapeshellarg($config_meshcentral_user);
$pass = escapeshellarg($config_meshcentral_secret);
echo "<h2>MeshCentral Asset Sync (All clients)</h2>";
// Small effort to support Windows (Note: The Apache service must be allowed to interact with desktop)
if((strtoupper(substr(PHP_OS, 0, 3)) == 'WIN')){
// Grab a list of all devices
$mesh_devices = json_decode(shell_exec("node meshctrl.js --url $url --loginuser $usr --loginpass $pass ListDevices --json"), true);
}
else{
$mesh_devices = json_decode(shell_exec("./meshctrl.js --url $url --loginuser $usr --loginpass $pass ListDevices --json"), true);
}
foreach($mesh_devices as $device){
// Reset script timeout
set_time_limit(0);
$mesh_id = trim(strip_tags(mysqli_real_escape_string($mysqli,$device['_id'])));
$name = trim(strip_tags(mysqli_real_escape_string($mysqli,$device['name'])));
$client = trim(strip_tags(mysqli_real_escape_string($mysqli,$device['groupname'])));
$os = trim(strip_tags(mysqli_real_escape_string($mysqli,$device['osdesc'])));
$note = trim(strip_tags(mysqli_real_escape_string($mysqli,$device['desc'])));
$device_lookup_meshid_sql = mysqli_query($mysqli, "SELECT asset_id FROM assets WHERE asset_meshcentral_id = '$mesh_id' LIMIT 1");
$row = mysqli_fetch_array($device_lookup_meshid_sql);
$asset_id = $row['asset_id'];
// For each device in MeshCentral, check the name & group match for a client
if($device_lookup_meshid_sql && !empty($asset_id)){
// Found a match - sync the info
mysqli_query($mysqli, "UPDATE assets SET asset_name = '$name', asset_os = '$os', asset_notes = '$note' WHERE asset_id = '$asset_id'");
echo "Synced $name <br>";
}
else{
// Didn't find a match on the asset ID - check if we can create a new asset or link to existing
if(!empty($name) && !(empty($client))){
$device_lookup_name_sql = mysqli_query($mysqli, "SELECT asset_id FROM assets LEFT JOIN clients ON assets.asset_client_id = client_id WHERE asset_name = '$name' AND asset_meshcentral_id = '' AND client_meshcentral_group = '$client' LIMIT 1");
$row = mysqli_fetch_array($device_lookup_name_sql);
$asset_id = $row['asset_id'];
if($device_lookup_name_sql & !empty($asset_id)){
// We have found an existing asset that isn't linked to MeshCentral, let's link it
$os = trim(strip_tags(mysqli_real_escape_string($mysqli,$device['osdesc'])));
$note = trim(strip_tags(mysqli_real_escape_string($mysqli,$device['desc'])));
mysqli_query($mysqli, "UPDATE assets SET asset_os = '$os', asset_notes = '$note', asset_meshcentral_id = '$mesh_id' WHERE asset_id = '$asset_id'");
echo "Synced asset via asset ID $name <br>";
//Logging
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Asset', log_action = 'Modified', log_description = '$name linked to MeshCentral', log_created_at = NOW(), company_id = '1'");
}
else{
// Create a new asset, if we recognise the group
$group_lookup_sql = mysqli_query($mysqli, "SELECT client_id FROM clients WHERE client_meshcentral_group = '$client' LIMIT 1");
$row = mysqli_fetch_array($group_lookup_sql);
$client_id = $row['client_id'];
if($group_lookup_sql && !empty($client_id)){
mysqli_query($mysqli, "INSERT INTO assets SET asset_type = 'Desktop', asset_name = '$name', asset_os = '$os', asset_notes = '$note', asset_meshcentral_id = '$mesh_id', asset_client_id = '$client_id', company_id = '1'");
//Logging
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Asset', log_action = 'Created', log_description = '$name via MeshCentral sync', log_created_at = NOW(), company_id = '1'");
echo "Created new asset $name";
}
}
}
}
}
echo "<br><br>";
echo "<b>Sync Complete!</b>";

2786
plugins/meshctrl/meshctrl.js Normal file

File diff suppressed because it is too large Load Diff

51
plugins/meshctrl/package-lock.json generated Normal file
View File

@ -0,0 +1,51 @@
{
"name": "meshctrl",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"minimist": "^1.2.5",
"ws": "^8.5.0"
}
},
"node_modules/minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"node_modules/ws": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
"integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
},
"dependencies": {
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"ws": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
"integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
"requires": {}
}
}
}

View File

@ -0,0 +1,6 @@
{
"dependencies": {
"minimist": "^1.2.5",
"ws": "^8.5.0"
}
}

View File

@ -715,8 +715,11 @@ if(isset($_POST['verify'])){
if(isset($_POST['edit_general_settings'])){
$config_base_url = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['config_base_url'])));
$mesh_uri = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['meshcentral_uri'])));
$mesh_user = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['meshcentral_user'])));
$mesh_secret = encryptLoginEntry((mysqli_real_escape_string($mysqli,$_POST['meshcentral_secret'])));
mysqli_query($mysqli,"UPDATE settings SET config_base_url = '$config_base_url' WHERE company_id = $session_company_id");
mysqli_query($mysqli,"UPDATE settings SET config_base_url = '$config_base_url', config_meshcentral_uri = '$mesh_uri', config_meshcentral_user = '$mesh_user', config_meshcentral_secret = '$mesh_secret' WHERE company_id = $session_company_id");
//Logging
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Settings', log_action = 'Modify', log_description = '$session_name modified general settings', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_created_at = NOW(), log_user_id = $session_user_id, company_id = $session_company_id");
@ -1195,8 +1198,9 @@ if(isset($_POST['edit_client'])){
$currency_code = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['currency_code'])));
$net_terms = intval($_POST['net_terms']);
$notes = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['notes'])));
$mesh_group = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['meshcentral_group'])));
mysqli_query($mysqli,"UPDATE clients SET client_name = '$name', client_type = '$type', client_website = '$website', client_referral = '$referral', client_currency_code = '$currency_code', client_net_terms = $net_terms, client_notes = '$notes', client_updated_at = NOW() WHERE client_id = $client_id AND company_id = $session_company_id");
mysqli_query($mysqli,"UPDATE clients SET client_name = '$name', client_type = '$type', client_website = '$website', client_referral = '$referral', client_currency_code = '$currency_code', client_net_terms = $net_terms, client_notes = '$notes', client_meshcentral_group = '$mesh_group', client_updated_at = NOW() WHERE client_id = $client_id AND company_id = $session_company_id");
//Tags
//Delete existing tags

View File

@ -18,6 +18,44 @@
<small class="form-text text-muted">This is used by cron to send the correct url for invoice guest views</small>
</div>
<hr>
<div class="form-group">
<label>MeshCentral URI & Port</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-globe"></i></span>
</div>
<input type="text" class="form-control" name="meshcentral_uri" placeholder="Format: wss://mesh.itflow.org:443" value="<?php echo $config_meshcentral_uri; ?>">
</div>
</div>
<div class="form-group">
<label>MeshCentral Token User</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="meshcentral_user" placeholder="~t:ABCDEF" value="<?php echo $config_meshcentral_user; ?>">
</div>
</div>
<div class="form-group">
<label>MeshCentral Token Password</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-keyboard"></i></span>
</div>
<input type="password" class="form-control" name="meshcentral_secret" placeholder="Auto-generated on MeshCentral" value="<?php echo $config_meshcentral_secret; ?>">
</div>
</div>
<div class="form-group">
<div class="alert alert-warning" role="alert">
This token/user only requires <b>read access</b> to MeshCentral and is stored in <b>plaintext</b>.
</div>
</div>
<hr>
<button type="submit" name="edit_general_settings" class="btn btn-primary">Save</button>