Skip to content

Commit

Permalink
#52 Refactor the MISP export dialog to merge confirmation and target …
Browse files Browse the repository at this point in the history
…selection
  • Loading branch information
nadouani committed Sep 11, 2017
1 parent 4e795d0 commit 594e4f2
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 143 deletions.
1 change: 1 addition & 0 deletions ui/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
<script src="scripts/controllers/case/CaseCloseModalCtrl.js"></script>
<script src="scripts/controllers/case/CaseCreationCtrl.js"></script>
<script src="scripts/controllers/case/CaseDetailsCtrl.js"></script>
<script src="scripts/controllers/case/CaseExportDialogCtrl.js"></script>
<script src="scripts/controllers/case/CaseLinksCtrl.js"></script>
<script src="scripts/controllers/case/CaseListCtrl.js"></script>
<script src="scripts/controllers/case/CaseMainCtrl.js"></script>
Expand Down
88 changes: 88 additions & 0 deletions ui/app/scripts/controllers/case/CaseExportDialogCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
(function() {
'use strict';

angular
.module('theHiveControllers')
.controller('CaseExportDialogCtrl', function(MispSrv, NotificationSrv, clipboard, $uibModalInstance, caze, config) {
var self = this;

this.caze = caze;
this.mode = '';
this.servers = config.servers;
this.failures = [];

this.existingExports = {};
this.loading = false;

_.each(_.filter(this.caze.stats.alerts || [], function(item) {
return item.type === 'misp';
}), function(item) {
self.existingExports[item.source] = true;
});

var extractExportErrors = function (errors) {
var result = [];

result = errors.map(function(item) {
return {
data: item.object.dataType === 'file' ? item.object.attachment.name : item.object.data,
message: item.message
};
});

return result;
}

this.copyToClipboard = function() {
clipboard.copyText(_.pluck(self.failures, 'data').join('\n'));
$uibModalInstance.dismiss();
}

this.cancel = function() {
$uibModalInstance.dismiss();
};

this.confirm = function() {
$uibModalInstance.close();
};

this.export = function(server) {
self.loading = true;
self.failures = [];

MispSrv.export(self.caze.id, server)
.then(function(response){
var success = 0,
failure = 0;

if (response.status === 207) {
success = response.data.success.length;
failure = response.data.failure.length;

self.mode = 'error';
self.failures = extractExportErrors(response.data.failure);

NotificationSrv.log('The case has been successfully exported, but '+ failure +' observable(s) failed', 'warning');
} else {
success = angular.isObject(response.data) ? 1 : response.data.length;
NotificationSrv.log('The case has been successfully exported with ' + success+ ' observable(s)', 'success');
$uibModalInstance.close();
}
self.loading = false;

}, function(err) {
if(!err) {
return;
}

if (err.status === 400) {
self.mode = 'error';
self.failures = extractExportErrors(err.data);
} else {
NotificationSrv.error('CaseExportCtrl', 'An unexpected error occurred while exporting case', err.status);
}
self.loading = false;
});
}
});
})();
101 changes: 20 additions & 81 deletions ui/app/scripts/controllers/case/CaseMainCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@
$scope.caze = caze;
$rootScope.title = 'Case #' + caze.caseId + ': ' + caze.title;

$scope.initExports = function() {
$scope.existingExports = _.filter($scope.caze.stats.alerts || [], function(item) {
return item.type === 'misp';
}).length;
};
$scope.initExports();

$scope.updateMetricsList = function() {
MetricsCacheSrv.all().then(function(metrics) {
$scope.allMetrics = _.omit(metrics, _.keys($scope.caze.metrics));
Expand Down Expand Up @@ -198,99 +205,31 @@
});
};


var extractExportErrors = function (errors) {
var result = [];

result = errors.map(function(item) {
return {
data: item.object.dataType === 'file' ? item.object.attachment.name : item.object.data,
message: item.message
};
});

return result;
}

var showExportErrors = function(errors) {
$uibModal.open({
templateUrl: 'views/partials/misp/error.dialog.html',
controller: function(clipboard, $uibModalInstance, failures) {
this.failures = failures;
this.cancel = function() {
$uibModalInstance.dismiss();
}

this.copyToClipboard = function() {
clipboard.copyText(_.pluck(failures, 'data').join('\n'));
$uibModalInstance.dismiss();
}
},
controllerAs: 'dialog',
size: 'lg',
resolve: {
failures: function() {
return errors;
}
}
})
}

$scope.shareCase = function() {
var modalInstance = $uibModal.open({
templateUrl: 'views/partials/misp/case.export.confirm.html',
controller: function($uibModalInstance, data) {
this.caze = data;
this.cancel = function() {
$uibModalInstance.dismiss();
}

this.confirm = function() {
$uibModalInstance.close();
}
},
controller: 'CaseExportDialogCtrl',
controllerAs: 'dialog',
size: 'lg',
resolve: {
data: function() {
caze: function() {
return $scope.caze;
},
config: function() {
return $scope.appConfig.connectors.misp;
}
}
});

modalInstance.result.then(function() {
var mispConfig = $scope.appConfig.connectors.misp;
return MispSrv.getServer(mispConfig)
}).then(function(server) {
return MispSrv.export($scope.caseId, server);
return CaseSrv.get({
'caseId': $scope.caseId,
'nstats': true
}).$promise;
}).then(function(data) {
$scope.caze = data.toJSON();
$scope.initExports();
})
.then(function(response){
var success = 0,
failure = 0;

if (response.status === 207) {
success = response.data.success.length;
failure = response.data.failure.length;

showExportErrors(extractExportErrors(response.data.failure));

NotificationSrv.log('The case has been successfully exported, but '+ failure +' observable(s) failed', 'warning');
} else {
success = angular.isObject(response.data) ? 1 : response.data.length;
NotificationSrv.log('The case has been successfully exported with ' + success+ ' observable(s)', 'success');
}

}, function(err) {
if(!err) {
return;
}

if (err.status === 400) {
showExportErrors(extractExportErrors(err.data));
} else {
NotificationSrv.error('CaseExportCtrl', 'An unexpected error occurred while exporting case', response.status);
}
});

};

/**
Expand Down
29 changes: 0 additions & 29 deletions ui/app/scripts/services/MispSrv.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,35 +118,6 @@
return defer.promise;
},

promptForInstance: function(servers) {
var modalInstance = $uibModal.open({
templateUrl: 'views/partials/misp/choose-instance-dialog.html',
controller: 'ServerInstanceDialogCtrl',
controllerAs: 'vm',
size: '',
resolve: {
servers: function() {
return servers;
}
}
});

return modalInstance.result;
},

getServer: function(mispConfig) {
if(!mispConfig || !mispConfig.enabled || !mispConfig.servers) {
return $q.reject();
}

var servers = mispConfig.servers;
if (servers.length === 1) {
return $q.resolve(servers[0]);
} else {
return factory.promptForInstance(servers);
}
},

export: function(caseId, server) {
return $http.post(baseUrl + '/export/' + caseId + '/' + server, {});
}
Expand Down
2 changes: 1 addition & 1 deletion ui/app/views/partials/case/case.panelinfo.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ <h3 class="box-title">
<span class="ml-xs pull-right">
<a href ng-click="shareCase()" class="text-primary noline" uib-tooltip="Share case">
<i class="text-primary fa fa-share"></i>
Share
Share ({{existingExports}})
</a>
</span>

Expand Down
44 changes: 40 additions & 4 deletions ui/app/views/partials/misp/case.export.confirm.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,47 @@
<h3 class="modal-title">MISP Export</h3>
</div>
<div class="modal-body">
<p>
Are you sure you want to export the case <strong>{{dialog.caze.title}}</strong>.
</p>
<div ng-if="dialog.mode !== 'error'">
<p>
You are about to export the case <strong>{{dialog.caze.title}}</strong> to on of the following MISP servers:
</p>

<table class="mt-m table table-striped valigned">
<tbody class="pv-xs" ng-repeat="server in dialog.servers">
<tr>
<td><h4>{{server}}</h4></td>
<td width="150">
<button class="btn btn-block pull-right"
ng-class="{'btn-primary': dialog.existingExports[server], 'btn-warning': !dialog.existingExports[server]}"
ng-click="dialog.export(server)"
ng-disabled="dialog.loading">{{dialog.existingExports[server] ? 'Update' : 'Export'}}</button>
</td>
</tr>
</tbody>
</table>
</div>

<div ng-if="dialog.mode === 'error'">
<div class="alert alert-danger">
Failed to export the following observables
</div>
<table class="table table-striped">
<thead>
<th>Observable</th>
<th>Reason</th>
</thead>
<tbody>
<tr ng-repeat="o in dialog.failures">
<td class="wrap">{{o.data | fang}}</td>
<td class="nowrap">{{o.message}}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="modal-footer text-left">
<button class="btn btn-default" ng-click="dialog.cancel()" type="button">Cancel</button>
<button class="btn btn-primary pull-right" ng-click="dialog.confirm()">Confirm</button>
<button class="btn btn-primary pull-right" ng-if="dialog.mode === 'error'" ng-click="dialog.copyToClipboard()" type="button">
<i class="fa fa-copy"></i> Copy to clipboard
</button>
</div>
28 changes: 0 additions & 28 deletions ui/app/views/partials/misp/error.dialog.html

This file was deleted.

0 comments on commit 594e4f2

Please sign in to comment.