Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DetectX Module #916

Merged
merged 9 commits into from
Dec 19, 2017
28 changes: 28 additions & 0 deletions app/modules/detectx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
DetectX Module
==============

Module pulls data from DetectX results json. It does not **run** DetectX, admins are responsible for creating their own launch daemon that runs DetectX and provides the results data to:
```
/usr/local/munki/preflight.d/cache/detectx.json
```

Example Launch Daemon
``` xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>DetectX All User Run</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/DetectX Swift.app/Contents/MacOS/DetectX Swift</string>
<string>search</string>
<string>-aj</string>
<string>/usr/loca/munki/preflight.d/cache/detectx.json</string>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path is missing an 'l', should be /usr/local/munki/preflight.d/cache/detectx.json

</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
```
66 changes: 66 additions & 0 deletions app/modules/detectx/detectx_controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

/**
* homebrew module class
*
* @package munkireport
* @author tuxudo
**/
class Detectx_controller extends Module_controller
{

/*** Protect methods with auth! ****/
function __construct()
{
// Store module path
$this->module_path = dirname(__FILE__);
}

/**
* Default method
* @author tuxudo
*
**/
function index()
{
echo "You've loaded the detectx module!";
}
public function get_stats()
{
$obj = new View();
if (! $this->authorized()) {
$obj->view('json', array('msg' => 'Not authorized'));
return;
}

$queryobj = new Detectx_model();
$sql = "SELECT COUNT(1) as total,
COUNT(CASE WHEN `status` = 'Clean' THEN 1 END) AS Clean,
COUNT(CASE WHEN `status` = 'Infected' THEN 1 END) AS Infected
FROM detectx";
$obj->view('json', array('msg' => current($queryobj->query($sql))));
}

/**
* Retrieve data in json format
*
**/
public function get_data($serial_number = '')
{
$obj = new View();

if (! $this->authorized()) {
$obj->view('json', array('msg' => 'Not authorized'));
return;
}

$queryobj = new Detectx_model;
$detectx_tab = array();
foreach($queryobj->retrieve_records($serial_number) as $detectxEntry) {
$detectx_tab[] = $detectxEntry->rs;
}

$obj->view('json', array('msg' => $detectx_tab));
}

} // END class Detectx_controller
67 changes: 67 additions & 0 deletions app/modules/detectx/detectx_model.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php
class Detectx_model extends \Model {

function __construct($serial='')
{
parent::__construct('id', 'detectx'); //primary key, tablename
$this->rs['id'] = '';
$this->rs['serial_number'] = $serial;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a UNIQUE rt statement: $this->rt['serial_number'] = 'VARCHAR(255) UNIQUE';

$this->rs['searchdate'] = 0; $this->rt['searchdate'] = 'BIGINT';
$this->rs['numberofissues'] = 0;
$this->rs['status'] = '';
$this->rs['issues'] = ''; $this->rt['issues'] = 'TEXT';


// Schema version, increment when creating a db migration
$this->schema_version = 0;

// Add indexes
$this->idx[] = array('numberofissues');
$this->idx[] = array('status');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add an index on search date too.


// Create table if it does not exist
$this->create_table();

$this->serial_number = $serial;
}

// ------------------------------------------------------------------------


/**
* Process data sent by postflight
*
* @param string data
* @author wardsparadox
* based on homebrew by tuxudo
**/
function process($json)
{
// Check if data was uploaded
if ( ! $json ){
throw new Exception("Error Processing Request: No JSON file found", 1);
}
// Delete previous set
$this->deleteWhere('serial_number=?', $this->serial_number);

// Process json into object thingy
$data = json_decode($json, true);
$this->searchdate = strtotime($data['searchdate']);
$len = count($data['issues']);
if ($len > 0)
{
foreach($data['issues'] as $issue){
$this->status = "Infected";
$this->issues .= ($issue . ";");
$this->numberofissues += 1;
}
}
else {
$this->status = "Clean";
$this->issues = 'No Issues Detected';
$this->numberofissues = 0;

}
$this->save();
}
}
17 changes: 17 additions & 0 deletions app/modules/detectx/locales/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"listing": {
"reporttitle": "DetectX Report",
"clienttitle": "DetectX",
"clienttab": "DetectX",
"issues": "Issues",
"numberofissues": "Number of Issues",
"searchdate": "Search Date",
"status": "Status"
},
"widget": {
"title": "DetectX Status",
"clean": "Clean",
"infected": "Infected"
},
"title": "DetectX"
}
14 changes: 14 additions & 0 deletions app/modules/detectx/provides.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
//
return array(
'client_tabs' => array(
'detectx-tab' => array('view' => 'detectx_tab', 'i18n' => 'detectx.clienttitle', 'badge' => 'detectx-cnt'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

detectx.clienttitle does not exist in the locale.json. You may want to change that to detectx.title (this controls the name in the dropdown in the client detail page)

),
'listings' => array(
'detectx' => array('view' => 'detectx_listing', 'i18n' => 'detectx.clienttitle'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

detectx.clienttitle does not exist in the locale.json. You may want to change that to detectx.title (this controls the name in the dropdown in the listing menu)

),
'widgets' => array(
'detectx' => array('view' => 'detectx_widget'),
),

);
9 changes: 9 additions & 0 deletions app/modules/detectx/scripts/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

# detectx controller
#CTL="${BASEURL}index.php?/module/detectx/"
# Set preference to include this file in the preflight check
setreportpref "detectx" "${CACHEPATH}detectx.json"
if [ ! -f "${CACHEPATH}detectx.json" ]; then
touch "${CACHEPATH}detectx.json"
fi
4 changes: 4 additions & 0 deletions app/modules/detectx/scripts/uninstall.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

# Remove homebrew.json file
rm -f "${CACHEPATH}detectx.json"
114 changes: 114 additions & 0 deletions app/modules/detectx/views/detectx_listing.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php $this->view('partials/head'); ?>

<?php //Initialize models needed for the table
new Machine_model;
new Reportdata_model;
new Detectx_model;
?>

<div class="container">
<div class="row">
<div class="col-lg-12">

<h3><span data-i18n="detectx.listing.reporttitle"></span> <span id="total-count" class='label label-primary'>…</span></h3>

<table class="table table-striped table-condensed table-bordered">

<thead>
<tr>
<th data-i18n="listing.computername" data-colname='machine.computer_name'></th>
<th data-i18n="serial" data-colname='reportdata.serial_number'></th>
<th data-i18n="detectx.listing.searchdate" data-colname='detectx.searchdate'></th>
<th data-i18n="detectx.listing.status" data-colname='detectx.status'></th>
<th data-i18n="detectx.listing.numberofissues" data-colname='detectx.numberofissues'></th>
</tr>
</thead>

<tbody>
<tr>
<td data-i18n="listing.loading" colspan="10" class="dataTables_empty"></td>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

colspan= should be equal to the total amount of columns in the listing.

</tr>
</tbody>

</table>
</div> <!-- /span 12 -->
</div> <!-- /row -->
</div> <!-- /container -->

<script type="text/javascript">

$(document).on('appUpdate', function(e){

var oTable = $('.table').DataTable();
oTable.ajax.reload();
return;

});

$(document).on('appReady', function(e, lang) {

// Get modifiers from data attribute
var mySort = [], // Initial sort
hideThese = [], // Hidden columns
col = 0, // Column counter
runtypes = [], // Array for runtype column
columnDefs = [{ visible: false, targets: hideThese }]; //Column Definitions

$('.table th').map(function(){

columnDefs.push({name: $(this).data('colname'), targets: col});

if($(this).data('sort')){
mySort.push([col, $(this).data('sort')])
}

if($(this).data('hide')){
hideThese.push(col);
}

col++
});

oTable = $('.table').dataTable( {
ajax: {
url: appUrl + '/datatables/data',
type: "POST",
data: function(d){
d.mrColNotEmpty = "searchdate";

// Check for column in search
if(d.search.value){
$.each(d.columns, function(index, item){
if(item.name == 'detectx.' + d.search.value){
d.columns[index].search.value = '> 0';
}
});

}

if(d.search.value.match(/^\d+\.\d+(\.(\d+)?)?$/)){
var search = d.search.value.split('.').map(function(x){return ('0'+x).slice(-2)}).join('');
d.search.value = search;
}
}
},
dom: mr.dt.buttonDom,
buttons: mr.dt.buttons,
order: mySort,
columnDefs: columnDefs,
createdRow: function( nRow, aData, iDataIndex ) {
// Update name in first column to link
var name=$('td:eq(0)', nRow).html();
if(name == ''){name = "No Name"};
var sn=$('td:eq(1)', nRow).html();
var link = mr.getClientDetailLink(name, sn, '#tab_detectx-tab');
$('td:eq(0)', nRow).html(link);
var checkin = parseInt($('td:eq(2)', nRow).html());
var date = new Date(checkin * 1000);
$('td:eq(2)', nRow).html('<span title="'+i18n.t('detectx.listing.searchdate')+" "+moment(date).format('llll')+'">'+moment(date).fromNow()+'</span>');
}
});
});
</script>

<?php $this->view('partials/foot'); ?>
43 changes: 43 additions & 0 deletions app/modules/detectx/views/detectx_tab.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<div id="detectx-tab"></div>
<h2 data-i18n="detectx.listing.clienttab"></h2>

<script>
$(document).on('appReady', function(){
$.getJSON(appUrl + '/module/detectx/get_data/' + serialNumber, function(data){
// Set count to detectx's number of issues
$('#detectx-cnt').text(data[0].numberofissues);
var skipThese = ['id','serial_number'];
$.each(data, function(i,d){

// Generate rows from data
var rows = ''
for (var prop in d){
// Skip skipThese
if(skipThese.indexOf(prop) == -1){
if(prop == 'searchdate'){
var reporteddate = d[prop];
var date = new Date(reporteddate * 1000)
rows = rows + '<tr><th>'+i18n.t('detectx.listing.'+prop)+'</th><td>'+moment(date).format('llll')+'</td></tr>';
}
else {
if(prop == 'issues'){
var issue = '';
issue = d[prop].split(';').join('<br />');
rows = rows + '<tr><th>'+i18n.t('detectx.listing.'+prop)+'</th><td>'+issue+'</td></tr>';
}
else{
rows = rows + '<tr><th>'+i18n.t('detectx.listing.'+prop)+'</th><td>'+d[prop]+'</td></tr>';
}
}
}
}
$('#detectx-tab')
.append($('<table style="max-width: 900px">')
.addClass('table table-responsive table-striped table-condensed')
.append($('<tbody>')
.append(rows)))
})

});
});
</script>
Loading