Skip to content

Commit

Permalink
Merge pull request #14 from munkireport/bundle-version
Browse files Browse the repository at this point in the history
Update module
  • Loading branch information
tuxudo authored Feb 27, 2021
2 parents 7fdb14a + 26111a3 commit 297720d
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 231 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ Shows information about applications on the client.

Data can be viewed under the Applications tab on the client details page or using the Applications listing view

Database:

Table Schema
------
* name - varchar(255) - name of the application
* path - TEXT - application's path
* last_modified - BIGINT - date application was last modified (epoch)
Expand All @@ -15,3 +17,4 @@ Database:
* info - TEXT - info about the application
* has64bit - int - 0/1 does application contain 64-bit code
* signed_by - varchar(255) - code signing of application
* bundle_version - varchar(255) - the application's bundle version from the CFBundleVersion key
59 changes: 25 additions & 34 deletions applications_controller.php
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -16,55 +16,46 @@ function __construct()
$this->module_path = dirname(__FILE__);
}

/**
/**
* Default method
* @author tuxudo
*
**/
function index()
function index()
{
echo "You've loaded the applications module!";
}

/**
* Retrieve data in json format
/**
* Retrieve data in json format for widget
*
**/
public function get_data($serial_number = '')
public function get_32_bit_apps()
{
$obj = new View();
$sql = "SELECT COUNT(CASE WHEN name <> '' AND has64bit = 0 THEN 1 END) AS count, name
FROM applications
LEFT JOIN reportdata USING (serial_number)
WHERE has64bit = 0
".get_machine_group_filter('AND')."
GROUP BY name
ORDER BY count DESC";

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

$queryobj = new Applications_model();

$sql = "SELECT name, path, lastModified, obtained_from, runtime_environment, version, info, signed_by, has64BitIntelCode
FROM applications
WHERE serial_number = '$serial_number'";

$applications_tab = $queryobj->query($sql);

$applications = new Applications_model;
$obj->view('json', array('msg' => current(array('msg' => $applications_tab))));
}
jsonView($queryobj->query($sql));
}

/**
* Retrieve data in json format for widget
/**
* Retrieve data in json format
*
**/
public function get_32_bit_apps()
{
$obj = new View();
public function get_data($serial_number = '')
{
$sql = "SELECT name, path, last_modified, obtained_from, runtime_environment, version, bundle_version, info, signed_by, has64bit
FROM applications
WHERE serial_number = '$serial_number'";

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

$apps_32 = new Applications_model;
$obj->view('json', array('msg' => $apps_32->get_32_bit_apps()));
}
$queryobj = new Applications_model();
jsonView($queryobj->query($sql));
}

} // END class Applications_controller
} // End class Applications_controller
175 changes: 79 additions & 96 deletions applications_model.php
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -4,117 +4,100 @@

class Applications_model extends \Model {

function __construct($serial='')
{
parent::__construct('id', 'applications'); //primary key, tablename
$this->rs['id'] = '';
$this->rs['serial_number'] = $serial;
$this->rs['name'] = '';
$this->rs['path'] = '';
$this->rs['last_modified'] = 0;
$this->rs['obtained_from'] = '';
$this->rs['runtime_environment'] = '';
$this->rs['version'] = '';
$this->rs['info'] = '';
$this->rs['signed_by'] = '';
$this->rs['has64bit'] = 0; // True or False
function __construct($serial='')
{
parent::__construct('id', 'applications'); //primary key, tablename
$this->rs['id'] = '';
$this->rs['serial_number'] = $serial;
$this->rs['name'] = '';
$this->rs['path'] = '';
$this->rs['last_modified'] = 0;
$this->rs['obtained_from'] = '';
$this->rs['runtime_environment'] = '';
$this->rs['version'] = '';
$this->rs['info'] = '';
$this->rs['signed_by'] = '';
$this->rs['has64bit'] = 0; // True or False
$this->rs['bundle_version'] = '';

$this->serial_number = $serial;
}
$this->serial_number = $serial;
}

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

/**
* Retrieve data in json format for widget
*
**/
public function get_32_bit_apps()
{
$out = array();
$sql = "SELECT COUNT(CASE WHEN name <> '' AND has64bit = 0 THEN 1 END) AS count, name
FROM applications
LEFT JOIN reportdata USING (serial_number)
WHERE has64bit = 0
".get_machine_group_filter('AND')."
GROUP BY name
ORDER BY count DESC";

$out = $this->query($sql);
return $out;
}

/**
* Process data sent by postflight
*
* @param string data
* @author tuxudo
**/
function process($plist)
{

if ( ! $plist){
throw new Exception("Error Processing Request: No property list found", 1);
}

// Delete previous set
$this->deleteWhere('serial_number=?', $this->serial_number);
// ------------------------------------------------------------------------

/**
* Process data sent by postflight
*
* @param string data
* @author tuxudo
**/
function process($plist)
{
// Check if we have data
if ( ! $plist){
throw new Exception("Error Processing Request: No property list found", 1);
}

// Delete previous set
$this->deleteWhere('serial_number=?', $this->serial_number);

$parser = new CFPropertyList();
$parser->parse($plist, CFPropertyList::FORMAT_XML);
$myList = $parser->toArray();

$typeList = array(
'name' => '',
'last_modified' => '',
'obtained_from' => 'unknown',
'path' => '',
'runtime_environment' => '',
'version' => '',
'info' => '',
'signed_by' => '',
'has64bit' => 0, // Yes or No
'bundle_version' => '' // Yes or No
);

$parser = new CFPropertyList();
$parser->parse($plist, CFPropertyList::FORMAT_XML);
$myList = $parser->toArray();

$typeList = array(
'name' => '',
'last_modified' => '',
'obtained_from' => 'unknown',
'path' => '',
'runtime_environment' => '',
'version' => '',
'info' => '',
'signed_by' => '',
'has64bit' => 0 // Yes or No
);

// List of paths to ignore
$bundlepath_ignorelist = is_array(conf('bundlepath_ignorelist')) ? conf('bundlepath_ignorelist') : array();
$path_regex = ':^'.implode('|', $bundlepath_ignorelist).'$:';
foreach ($myList as $app) {
// Check if we have a name
if( ! array_key_exists("name", $app)){
continue;
}

// Process each app
foreach ($myList as $app) {
// Check if we have a name
if( ! array_key_exists("name", $app)){
continue;
}

// Skip path
if (preg_match($path_regex, $app['path'])) {
continue;
}
if (preg_match($path_regex, $app['path'])) {
continue;
}

// Fix signed_by entries
if (array_key_exists("signed_by",$app)) {
$app['signed_by'] = str_replace(array('Developer ID Application: '), array(''), $app['signed_by']);
}

// Fix last_modified date
if (array_key_exists("last_modified",$app)) {
$temptime = $app['last_modified'];
$date = new DateTime("@$temptime");
$app['last_modified'] = $date->format('U');
}

// Process each app for saving
foreach ($typeList as $key => $value) {
$this->rs[$key] = $value;
if(array_key_exists($key, $app))
{
$this->rs[$key] = $app[$key];
}
}
// Save application
$this->id = '';
$this->save();
}
}
}
foreach ($typeList as $key => $value) {
$this->rs[$key] = $value;
if(array_key_exists($key, $app))
{
$this->rs[$key] = $app[$key];
}
}

// Save application
$this->id = '';
$this->save();
}
}
}
3 changes: 2 additions & 1 deletion locales/en.json
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"identified_developer": "Identified Developer",
"applications": "Applications",
"no_32_bit": "No 32-bit Applications",
"32_bit_apps": "32-bit Applications"
"32_bit_apps": "32-bit Applications",
"bundle_version": "Bundle Version"
}
27 changes: 27 additions & 0 deletions migrations/2021_02_26_000001_applications_add_bundle_version.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Capsule\Manager as Capsule;

class ApplicationsAddBundleVersion extends Migration
{
private $tableName = 'applications';

public function up()
{
$capsule = new Capsule();
$capsule::schema()->table($this->tableName, function (Blueprint $table) {
$table->string('bundle_version')->nullable();

$table->index('bundle_version');
});
}

public function down()
{
$capsule = new Capsule();
$capsule::schema()->table($this->tableName, function (Blueprint $table) {
$table->dropColumn('bundle_version');
});
}
}
29 changes: 17 additions & 12 deletions scripts/applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@
import plistlib
import sys

sys.path.insert(0, '/usr/local/munki')
sys.path.insert(0, '/usr/local/munkireport')

from munkilib import FoundationPlist

def get_app_bundle_version(app_path):
'''Return the CFBundleVersion of the app based on its path'''

try:
info_plist = FoundationPlist.readPlist(app_path+"/Contents/Info.plist")
return info_plist['CFBundleVersion']

except Exception:
return ""

def get_applications_info():
'''Uses system profiler to get applications for this machine.'''
Expand Down Expand Up @@ -41,6 +55,7 @@ def flatten_applications_info(array):
device['obtained_from'] = obj[item]
elif item == 'path':
device['path'] = obj[item]
device['bundle_version'] = get_app_bundle_version(obj[item])
elif item == 'runtime_environment':
device['runtime_environment'] = obj[item]
elif item == 'version':
Expand All @@ -60,17 +75,6 @@ def flatten_applications_info(array):

def main():
"""Main"""
# Create cache dir if it does not exist
cachedir = '%s/cache' % os.path.dirname(os.path.realpath(__file__))
if not os.path.exists(cachedir):
os.makedirs(cachedir)

# Skip manual check
if len(sys.argv) > 1:
if sys.argv[1] == 'manualcheck':
print 'Manual check: skipping'
exit(0)

# Set the encoding
reload(sys)
sys.setdefaultencoding('utf8')
Expand All @@ -79,8 +83,9 @@ def main():
result = dict()
info = get_applications_info()
result = flatten_applications_info(info)

# Write applications results to cache
cachedir = '%s/cache' % os.path.dirname(os.path.realpath(__file__))
output_plist = os.path.join(cachedir, 'applications.plist')
plistlib.writePlist(result, output_plist)
#print plistlib.writePlistToString(result)
Expand Down
Loading

0 comments on commit 297720d

Please sign in to comment.