diff --git a/CHANGELOG.md b/CHANGELOG.md index 09f89b2767..9fd8aa8a49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Change Log +## [4.1.11](https://github.com/TheHive-Project/TheHive/milestone/81) (2021-10-06) + +**Implemented enhancements:** + +- [Feature Request] Add the ability to update type of observable [\#2125](https://github.com/TheHive-Project/TheHive/issues/2125) + +**Closed issues:** + +- [Bug] Editing Someone Else's Dashboard [\#2212](https://github.com/TheHive-Project/TheHive/issues/2212) + +**Fixed bugs:** + +- [Bug] Dashboard are shared in read only by default [\#2190](https://github.com/TheHive-Project/TheHive/issues/2190) +- [Bug] Analyzer reports migration to 4.1.10 problem [\#2203](https://github.com/TheHive-Project/TheHive/issues/2203) + ## [4.1.10](https://github.com/TheHive-Project/TheHive/milestone/79) (2021-08-26) **Fixed bugs:** diff --git a/build.sbt b/build.sbt index dcf8e152e5..660593ad36 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ import Dependencies._ import com.typesafe.sbt.packager.Keys.bashScriptDefines import org.thp.ghcl.Milestone -val thehiveVersion = "4.1.10-1" +val thehiveVersion = "4.1.11-1" val scala212 = "2.12.13" val scala213 = "2.13.1" val supportedScalaVersions = List(scala212, scala213) diff --git a/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/JobSrv.scala b/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/JobSrv.scala index 34d5df72bf..7152f60ca6 100644 --- a/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/JobSrv.scala +++ b/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/services/JobSrv.scala @@ -195,7 +195,7 @@ class JobSrv @Inject() ( val tags = cortexJob.report.fold[Seq[ReportTag]](Nil)(_.summary.map(_.toAnalyzerTag(job.workerName))) for { observable <- get(job).observable.getOrFail("Observable") - _ <- reportTagSrv.updateTags(observable, job.workerName, tags) + _ <- reportTagSrv.updateTags(observable, tags) } yield () } else Success(()) diff --git a/frontend/app/scripts/controllers/case/CaseObservablesCtrl.js b/frontend/app/scripts/controllers/case/CaseObservablesCtrl.js index 95d3b631fb..c86a5fe39f 100644 --- a/frontend/app/scripts/controllers/case/CaseObservablesCtrl.js +++ b/frontend/app/scripts/controllers/case/CaseObservablesCtrl.js @@ -1,7 +1,7 @@ (function () { 'use strict'; angular.module('theHiveControllers').controller('CaseObservablesCtrl', - function ($scope, $q, $state, $stateParams, $filter, $uibModal, SecuritySrv, ModalUtilsSrv, FilteringSrv, StreamSrv, CaseTabsSrv, PaginatedQuerySrv, CaseArtifactSrv, NotificationSrv, AnalyzerSrv, CortexSrv, VersionSrv) { + function ($scope, $q, $state, $stateParams, $filter, $uibModal, SecuritySrv, ModalUtilsSrv, FilteringSrv, StreamSrv, CaseTabsSrv, PaginatedQuerySrv, ObservableTypeSrv, CaseArtifactSrv, NotificationSrv, AnalyzerSrv, CortexSrv, VersionSrv) { CaseTabsSrv.activateTab($state.current.data.tab); @@ -241,6 +241,12 @@ resolve: { selection: function () { return $scope.selection.artifacts; + }, + dataTypes: function () { + return ObservableTypeSrv.list() + .then(function (response) { + return response.data; + }); } } }); diff --git a/frontend/app/scripts/controllers/case/ObservableUpdateCtrl.js b/frontend/app/scripts/controllers/case/ObservableUpdateCtrl.js index f596796264..04691a77aa 100644 --- a/frontend/app/scripts/controllers/case/ObservableUpdateCtrl.js +++ b/frontend/app/scripts/controllers/case/ObservableUpdateCtrl.js @@ -1,34 +1,49 @@ -(function() { +(function () { 'use strict'; angular.module('theHiveControllers').controller('ObservableUpdateCtrl', - function($scope, $uibModalInstance, TagSrv, TaxonomyCacheSrv, selection) { + function ($scope, $uibModalInstance, TagSrv, TaxonomyCacheSrv, selection, dataTypes) { var self = this; this.selection = selection; - this.state = { - all: false, - enableTlp: false, - enableIoc: false, - enableSighted: false, - enableIgnoreSimilarity: false, - enableAddTags: false, - enableRemoveTags: false - }; + this.dataTypes = _.pluck(_.filter(dataTypes, function (item) { + return !item.isAttachment + }), 'name').sort(); + + this.$onInit = function () { + this.state = { + all: false, + enableDataType: false, + enableTlp: false, + enableIoc: false, + enableSighted: false, + enableIgnoreSimilarity: false, + enableAddTags: false, + enableRemoveTags: false + }; - this.activeTlp = 'active'; - this.params = { - ioc: false, - sighted: false, - ignoreSimilarity: false, - tlp: 2, - addTagNames: '', - removeTagNames: '' - }; + this.activeTlp = 'active'; + this.params = { + dataType: null, + ioc: false, + sighted: false, + ignoreSimilarity: false, + tlp: 2, + addTagNames: '', + removeTagNames: '' + }; + + var selectionTypes = _.unique(_.pluck(this.selection, 'dataType')); - this.toggleAll = function() { + this.canUpdateDataType = selectionTypes.length === 1 && this.dataTypes.indexOf(selectionTypes[0]) !== -1; + }; + this.toggleAll = function () { this.state.all = !this.state.all; + if (this.canUpdateDataType) { + this.state.enableDataType = this.state.all; + } + this.state.enableTlp = this.state.all; this.state.enableIoc = this.state.all; this.state.enableSighted = this.state.all; @@ -37,14 +52,14 @@ this.state.enableRemoveTags = this.state.all; }; - this.categorizeObservables = function() { + this.categorizeObservables = function () { var data = { withTags: [], withoutTags: [] }; - _.each(this.selection, function(item) { - if(item.tags.length > 0) { + _.each(this.selection, function (item) { + if (item.tags.length > 0) { data.withTags.push(item); } else { data.withoutTags.push(item); @@ -54,11 +69,17 @@ return data; }; - this.buildOperations = function(postData) { - var flags = _.pick(postData, 'ioc', 'sighted', 'ignoreSimilarity', 'tlp'); + this.buildOperations = function (postData) { + var flags = {}; + + if (this.canUpdateDataType) { + flags = _.pick(postData, 'dataType', 'ioc', 'sighted', 'ignoreSimilarity', 'tlp'); + } else { + flags = _.pick(postData, 'ioc', 'sighted', 'ignoreSimilarity', 'tlp'); + } // Handle updates without tag changes - if(!postData.addTags && !postData.removeTags) { + if (!postData.addTags && !postData.removeTags) { return [ { ids: _.pluck(this.selection, '_id'), @@ -70,28 +91,28 @@ // Handle update with tag changes var input = this.categorizeObservables(); var operations = []; - if(input.withoutTags.length > 0) { - var tags = (postData.addTags || []).filter(function(i) { + if (input.withoutTags.length > 0) { + var tags = (postData.addTags || []).filter(function (i) { return (postData.removeTags || []).indexOf(i) === -1; }); operations.push({ ids: _.pluck(input.withoutTags, '_id'), - patch: _.extend({}, flags ,{ + patch: _.extend({}, flags, { tags: _.unique(tags) }) }); } - if(input.withTags.length > 0) { - _.each(input.withTags, function(observable) { - tags = observable.tags.concat(postData.addTags || []).filter(function(i) { + if (input.withTags.length > 0) { + _.each(input.withTags, function (observable) { + tags = observable.tags.concat(postData.addTags || []).filter(function (i) { return (postData.removeTags || []).indexOf(i) === -1; }); operations.push({ ids: [observable._id], - patch: _.extend({}, flags ,{ + patch: _.extend({}, flags, { tags: _.unique(tags) }) }); @@ -101,49 +122,53 @@ return operations; }; - this.save = function() { + this.save = function () { var postData = {}; - if(this.state.enableIoc) { + if (this.state.enableDataType && this.canUpdateDataType) { + postData.dataType = this.params.dataType; + } + + if (this.state.enableIoc) { postData.ioc = this.params.ioc; } - if(this.state.enableSighted) { + if (this.state.enableSighted) { postData.sighted = this.params.sighted; } - if(this.state.enableIgnoreSimilarity) { + if (this.state.enableIgnoreSimilarity) { postData.ignoreSimilarity = this.params.ignoreSimilarity; } - if(this.state.enableTlp) { + if (this.state.enableTlp) { postData.tlp = this.params.tlp; } - if(this.state.enableAddTags) { + if (this.state.enableAddTags) { postData.addTags = _.pluck(this.params.addTags, 'text'); } - if(this.state.enableRemoveTags) { + if (this.state.enableRemoveTags) { postData.removeTags = _.pluck(this.params.removeTags, 'text'); } $uibModalInstance.close(this.buildOperations(postData)); }; - this.cancel = function() { + this.cancel = function () { $uibModalInstance.dismiss(); }; - this.getTags = function(query) { + this.getTags = function (query) { return TagSrv.autoComplete(query); }; - self.fromTagLibrary = function(field) { + self.fromTagLibrary = function (field) { TaxonomyCacheSrv.openTagLibrary() - .then(function(tags){ - if(field === 'add') { + .then(function (tags) { + if (field === 'add') { self.params.addTags = (self.params.addTags || []).concat(tags); self.toggleAddTags(); } else if (field === 'remove') { @@ -153,40 +178,49 @@ }) }; - this.toogleIoc = function() { + this.toggleDataType = function () { + if (!this.params.dataType || this.params.dataType.length === 0) { + this.params.dataType = null; + this.state.enableDataType = false; + } else { + this.state.enableDataType = true; + } + }; + + this.toogleIoc = function () { this.params.ioc = !this.params.ioc; this.state.enableIoc = true; }; - this.toogleSighted = function() { + this.toogleSighted = function () { this.params.sighted = !this.params.sighted; this.state.enableSighted = true; }; - this.toogleIgnoreSimilarity = function() { + this.toogleIgnoreSimilarity = function () { this.params.ignoreSimilarity = !this.params.ignoreSimilarity; this.state.enableIgnoreSimilarity = true; }; - this.toggleTlp = function(value) { + this.toggleTlp = function (value) { this.params.tlp = value; this.activeTlp = 'active'; this.state.enableTlp = true; }; - this.toggleAddTags = function() { + this.toggleAddTags = function () { this.state.enableAddTags = true; }; - this.toggleRemoveTags = function() { + this.toggleRemoveTags = function () { this.state.enableRemoveTags = true; }; - $scope.$watchCollection('$dialog.params.addTags', function(value) { + $scope.$watchCollection('$dialog.params.addTags', function (value) { self.params.addTagNames = _.pluck(value, 'text').join(','); }); - $scope.$watchCollection('$dialog.params.removeTags', function(value) { + $scope.$watchCollection('$dialog.params.removeTags', function (value) { self.params.removeTagNames = _.pluck(value, 'text').join(','); }); } diff --git a/frontend/app/views/partials/observables/observable.update.html b/frontend/app/views/partials/observables/observable.update.html index ebb3dc5bf1..1a7aac2b46 100644 --- a/frontend/app/views/partials/observables/observable.update.html +++ b/frontend/app/views/partials/observables/observable.update.html @@ -5,67 +5,94 @@
- Select the changes you want to apply to the selected observables. ({{$dialog.state.all ? 'Uncheck All' : 'Check all'}}) + Select the changes you want to apply to the selected observables. ({{$dialog.state.all ? 'Uncheck All' : 'Check all'}})
+