From 9e2d4127a5e67bec418fcd8a358f1a9d5106db8a Mon Sep 17 00:00:00 2001 From: Nabil Adouani Date: Mon, 9 Jul 2018 15:43:02 +0200 Subject: [PATCH] #110 Add responders list section to the UI --- www/src/app/components/header/header.html | 6 + www/src/app/index.module.js | 4 +- .../components/responders.list.controller.js | 37 ++++ .../components/responders.list.html | 32 +++ .../pages/responders/responders.controller.js | 109 ++++++++++ .../app/pages/responders/responders.module.js | 55 +++++ .../app/pages/responders/responders.page.html | 42 ++++ .../pages/responders/responders.service.js | 202 ++++++++++++++++++ 8 files changed, 486 insertions(+), 1 deletion(-) create mode 100644 www/src/app/pages/responders/components/responders.list.controller.js create mode 100644 www/src/app/pages/responders/components/responders.list.html create mode 100644 www/src/app/pages/responders/responders.controller.js create mode 100644 www/src/app/pages/responders/responders.module.js create mode 100644 www/src/app/pages/responders/responders.page.html create mode 100644 www/src/app/pages/responders/responders.service.js diff --git a/www/src/app/components/header/header.html b/www/src/app/components/header/header.html index e6601af2c..cfba5224d 100644 --- a/www/src/app/components/header/header.html +++ b/www/src/app/components/header/header.html @@ -39,6 +39,12 @@ Analyzers +
  • + + + Responders + +
  • diff --git a/www/src/app/index.module.js b/www/src/app/index.module.js index 6a3e7f91c..d1fc651ed 100755 --- a/www/src/app/index.module.js +++ b/www/src/app/index.module.js @@ -11,6 +11,7 @@ import indexComponents from './index.components'; import mainModule from './pages/main/main.module'; import loginModule from './pages/login/login.module'; import analyzersModule from './pages/analyzers/analyzers.module'; +import respondersModule from './pages/responders/responders.module'; import jobsModule from './pages/jobs/jobs.module'; import settingsModule from './pages/settings/settings.module'; @@ -46,6 +47,7 @@ const App = angular.module('cortex', [ loginModule.name, maintenanceModule.name, analyzersModule.name, + respondersModule.name, jobsModule.name, adminModule.name, settingsModule.name @@ -53,4 +55,4 @@ const App = angular.module('cortex', [ App.config(config).run(run); -export default App; +export default App; \ No newline at end of file diff --git a/www/src/app/pages/responders/components/responders.list.controller.js b/www/src/app/pages/responders/components/responders.list.controller.js new file mode 100644 index 000000000..eff999d53 --- /dev/null +++ b/www/src/app/pages/responders/components/responders.list.controller.js @@ -0,0 +1,37 @@ +'use strict'; + +export default class ResponderListController { + constructor($state, ResponderService, NotificationService) { + 'ngInject'; + + this.$state = $state; + this.ResponderService = ResponderService; + this.NotificationService = NotificationService; + } + + // run(analyzer, dataType) { + // analyzer.active = true; + // this.ResponderService.openRunModal([analyzer], { + // dataType: dataType + // }) + // .then(responses => { + // this.$state.go('main.jobs'); + + // responses.forEach(resp => { + // this.NotificationService.success( + // `${resp.data.analyzerName} started successfully on ${resp.data + // .data || resp.data.attachment.name}` + // ); + // }); + // }) + // .catch(err => { + // if (!_.isString(err)) { + // this.NotificationService.error( + // err.data.message || + // `An error occurred: ${err.statusText}` || + // 'An unexpected error occurred' + // ); + // } + // }); + // } +} \ No newline at end of file diff --git a/www/src/app/pages/responders/components/responders.list.html b/www/src/app/pages/responders/components/responders.list.html new file mode 100644 index 000000000..95b6ce0d6 --- /dev/null +++ b/www/src/app/pages/responders/components/responders.list.html @@ -0,0 +1,32 @@ +
    +
    +
    +
    No responders found.
    +
    +
    + +
    +
    +
    +
    +

    + {{responder.name}} + + Version: {{responder.version}} + + Author: {{responder.author}} + + License: {{responder.license}} +

    +
    + {{responder.description}} +
    +
    + Applies to: + {{type}}  +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/www/src/app/pages/responders/responders.controller.js b/www/src/app/pages/responders/responders.controller.js new file mode 100644 index 000000000..9244beea4 --- /dev/null +++ b/www/src/app/pages/responders/responders.controller.js @@ -0,0 +1,109 @@ +'use strict'; + +import _ from 'lodash/core'; + +import PageController from '../../core/controllers/PageController'; + +export default class RespondersController extends PageController { + constructor( + $log, + SearchService, + ResponderService, + NotificationService, + localStorageService + ) { + 'ngInject'; + + super('responders-page'); + + this.$log = $log; + this.ResponderService = ResponderService; + this.NotificationService = NotificationService; + this.localStorageService = localStorageService; + this.SearchService = SearchService; + + this.pagination = { + current: 1, + total: 0 + }; + + this.state = this.localStorageService.get('responders-page') || { + filters: { + search: null, + dataType: [] + }, + pagination: { + pageSize: 50, + current: 1 + } + }; + + this.filters = this.state.filters; + this.pagination = this.state.pagination; + } + + $onInit() { + this.load(1); + } + + buildQuery() { + let criteria = []; + + if (!_.isEmpty(this.filters.search)) { + criteria.push({ + _or: [{ + _like: { + _field: 'description', + _value: this.filters.search + } + }, + { + _like: { + _field: 'name', + _value: this.filters.search + } + } + ] + }); + } + + if (!_.isEmpty(this.filters.dataType)) { + criteria.push({ + _in: { + _field: 'dataTypeList', + _values: this.filters.dataType + } + }); + } + + return _.isEmpty(criteria) ? {} : + criteria.length === 1 ? + criteria[0] : { + _and: criteria + }; + } + + load(page) { + if (page) { + this.pagination.current = page; + } + + this.state.filters = this.filters; + this.state.pagination = { + pageSize: this.pagination.pageSize + }; + this.localStorageService.set('responders-page', this.state); + + this.SearchService.configure({ + objectType: 'responder', + filter: this.buildQuery(), + range: this.buildRange(), + sort: '+name' + }) + .search() + .then(response => { + this.responders = response.data; + this.pagination.total = parseInt(response.headers('x-total')) || 0; + }); + } +} \ No newline at end of file diff --git a/www/src/app/pages/responders/responders.module.js b/www/src/app/pages/responders/responders.module.js new file mode 100644 index 000000000..bfec563d0 --- /dev/null +++ b/www/src/app/pages/responders/responders.module.js @@ -0,0 +1,55 @@ +'use strict'; + +import RepondersController from './responders.controller'; +import tpl from './responders.page.html'; + +import RespondersListController from './components/responders.list.controller'; +import respondersListTpl from './components/responders.list.html'; + +import responderService from './responders.service.js'; + +//import './analyzers.page.scss'; + +const respondersModule = angular + .module('responders-module', ['ui.router']) + .config(($stateProvider, Roles) => { + 'ngInject'; + + $stateProvider.state('main.responders', { + url: 'responders', + component: 'respondersPage', + resolve: { + datatypes: ($q, ResponderService) => { + let defer = $q.defer(); + + ResponderService.list() + .then(() => { + defer.resolve(ResponderService.getTypes()); + }) + .catch(err => defer.reject(err)); + + return defer.promise; + } + }, + data: { + allow: [Roles.SUPERADMIN, Roles.ORGADMIN, Roles.ANALYZE] + } + }); + }) + .component('respondersPage', { + controller: RepondersController, + templateUrl: tpl, + bindings: { + datatypes: '<' + } + }) + .component('respondersList', { + controller: RespondersListController, + templateUrl: respondersListTpl, + bindings: { + responders: '<' + } + }) + .service('ResponderService', responderService); + +export default respondersModule; \ No newline at end of file diff --git a/www/src/app/pages/responders/responders.page.html b/www/src/app/pages/responders/responders.page.html new file mode 100644 index 000000000..76a701d26 --- /dev/null +++ b/www/src/app/pages/responders/responders.page.html @@ -0,0 +1,42 @@ +
    +

    Responders ({{$ctrl.pagination.total}})

    +
    + +
    +
    +
    +
    +
    + + + + + + + + + + + +
      +
      +
      +
      +
      + +
      + +
      +
      + diff --git a/www/src/app/pages/responders/responders.service.js b/www/src/app/pages/responders/responders.service.js new file mode 100644 index 000000000..0e8d020da --- /dev/null +++ b/www/src/app/pages/responders/responders.service.js @@ -0,0 +1,202 @@ +'use strict'; + +import _ from 'lodash'; + +// import AnalyzerRunController from './analyzer.run.controller'; +// import runAnalyzerModalTpl from './analyzer.run.modal.html'; + +export default class ResponderService { + constructor($log, $q, $http, $uibModal) { + 'ngInject'; + + this.$log = $log; + this.$q = $q; + this.$http = $http; + this.$uibModal = $uibModal; + + this.responderDefinitions = null; + this.responders = null; + this.dataTypes = {}; + } + + getTypes() { + return this.dataTypes; + } + + definitions(force) { + let defered = this.$q.defer(); + + if (force || this.responderDefinitions === null) { + this.$http.get('./api/responderdefinition').then( + response => { + this.responderDefinitions = _.keyBy(response.data, 'id'); + + defered.resolve(this.responderDefinitions); + }, + response => { + defered.reject(response); + } + ); + } else { + defered.resolve(this.responderDefinitions); + } + + return defered.promise; + } + + scan() { + let defer = this.$q.defer(); + + this.$http + .post('./api/responderdefinition/scan', {}) + .then(response => defer.resolve(response.data)) + .catch(err => defer.reject(err)); + + return defer.promise; + } + + list() { + let defered = this.$q.defer(); + + this.$http + .get('./api/responder', { + params: { + range: 'all', + sort: '+name' + } + }) + .then( + response => { + this.responders = response.data; + this.dataTypes = _.sortBy( + _.uniq(_.flatten(_.map(response.data, 'dataTypeList'))) + ); + + defered.resolve(response.data); + }, + response => { + defered.reject(response); + } + ); + + return defered.promise; + } + + configurations() { + let defer = this.$q.defer(); + this.$http + .get('./api/responderconfig') + .then(response => defer.resolve(response.data), err => defer.reject(err)); + + return defer.promise; + } + + getBaseConfig(baseConfig) { + let defer = this.$q.defer(); + + if (baseConfig) { + this.getConfiguration(baseConfig).then( + cfg => defer.resolve(cfg), + () => defer.resolve({}) + ); + } else { + defer.resolve({}); + } + + return defer.promise; + } + + getConfiguration(name) { + let defer = this.$q.defer(); + + this.$http + .get(`./api/responderconfig/${name}`) + .then(response => defer.resolve(response.data), err => defer.reject(err)); + + return defer.promise; + } + + saveConfiguration(name, values) { + let defer = this.$q.defer(); + + this.$http + .patch(`./api/responderconfig/${name}`, values) + .then(response => defer.resolve(response.data), err => defer.reject(err)); + + return defer.promise; + } + + // openRunModal(analyzers, observable) { + // let modalInstance = this.$uibModal.open({ + // animation: true, + // templateUrl: runAnalyzerModalTpl, + // controller: AnalyzerRunController, + // controllerAs: '$modal', + // size: 'lg', + // resolve: { + // observable: () => angular.copy(observable), + // analyzers: () => angular.copy(analyzers) + // } + // }); + + // return modalInstance.result.then(result => + // this.$q.all( + // result.analyzerIds.map(analyzerId => + // this.run(analyzerId, result.observable) + // ) + // ) + // ); + // } + + // run(id, artifact) { + // let postData; + + // if (artifact.dataType === 'file') { + // postData = { + // attachment: artifact.attachment, + // dataType: artifact.dataType, + // tlp: artifact.tlp + // }; + + // return this.$http({ + // method: 'POST', + // url: './api/analyzer/' + id + '/run', + // headers: { + // 'Content-Type': undefined + // }, + // transformRequest: data => { + // let formData = new FormData(), + // copy = angular.copy(data, {}), + // _json = {}; + + // angular.forEach(data, (value, key) => { + // if ( + // Object.getPrototypeOf(value) instanceof Blob || + // Object.getPrototypeOf(value) instanceof File + // ) { + // formData.append(key, value); + // delete copy[key]; + // } else { + // _json[key] = value; + // } + // }); + + // formData.append('_json', angular.toJson(_json)); + + // return formData; + // }, + // data: postData + // }); + // } else { + // postData = { + // data: artifact.data, + // attributes: { + // dataType: artifact.dataType, + // tlp: artifact.tlp + // } + // }; + + // return this.$http.post('./api/analyzer/' + id + '/run', postData); + // } + // } +} \ No newline at end of file