diff --git a/allowedSnakeCase.cjs b/allowedSnakeCase.cjs index 2ba2448ee2..b257daf6f7 100644 --- a/allowedSnakeCase.cjs +++ b/allowedSnakeCase.cjs @@ -206,8 +206,10 @@ module.exports = [ 'general_permissions', 'get_aggregate', 'get_aggregates_response', + 'get_capabilities', 'get_config_family_response', 'get_config_nvt_response', + 'get_features_response', 'get_feeds', 'get_feeds_response', 'get_identifier', @@ -236,13 +238,13 @@ module.exports = [ 'groups_data', 'gsad_response', 'has_av_duration', - '_has_caps', 'has_detection', 'has_duration', 'has_reference', 'has_selected', 'has_severity_filter', 'header_title', + 'help_response', 'highest_severity', 'high_per_host', 'host_allow', diff --git a/src/gmp/capabilities/__tests__/capabilities.js b/src/gmp/capabilities/__tests__/capabilities.js index 835994a957..ee6ad31798 100644 --- a/src/gmp/capabilities/__tests__/capabilities.js +++ b/src/gmp/capabilities/__tests__/capabilities.js @@ -215,6 +215,19 @@ describe('Capabilities tests', () => { } expect(i).toEqual(4); }); + + test('should handle features', () => { + const featureList = [ + {name: 'ENABLED_FEATURE_1', _enabled: 1}, + {name: 'DISABLED_FEATURE', _enabled: 0}, + {name: 'ENABLED_FEATURE_2', _enabled: 1}, + ]; + const caps = new Capabilities(['everything'], featureList); + expect(caps.featureEnabled('ENABLED_FEATURE_1')).toBe(true); + expect(caps.featureEnabled('DISABLED_FEATURE')).toBe(false); + expect(caps.featureEnabled('enabled_feature_2')).toBe(true); + expect(caps.featureEnabled('UNDEFINED_FEATURE')).toBe(false); + }); }); // vim: set ts=2 sw=2 tw=80: diff --git a/src/gmp/capabilities/capabilities.js b/src/gmp/capabilities/capabilities.js index e65a1832b2..f8baa0e991 100644 --- a/src/gmp/capabilities/capabilities.js +++ b/src/gmp/capabilities/capabilities.js @@ -3,10 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import {isDefined} from 'gmp/utils/identity'; -import {map} from 'gmp/utils/array'; +import {forEach, map} from 'gmp/utils/array'; import {pluralizeType} from 'gmp/utils/entitytype'; +import {parseBoolean} from 'gmp/parser'; const types = { audit: 'task', @@ -51,16 +51,27 @@ const convertType = type => { }; class Capabilities { - constructor(cap_names) { - this._has_caps = isDefined(cap_names); + constructor(cap_names, featuresList) { + this._hasCaps = isDefined(cap_names); + this._hasFeatures = isDefined(featuresList); let caps; + let featuresEnabled = {}; - if (this._has_caps) { + if (this._hasCaps) { caps = map(cap_names, name => name.toLowerCase()); } + if (this._hasFeatures) { + forEach(featuresList, feature => { + featuresEnabled[feature.name.toUpperCase()] = parseBoolean( + feature._enabled, + ); + }); + } + this._capabilities = new Set(caps); + this._featuresEnabled = featuresEnabled; } [Symbol.iterator]() { @@ -68,7 +79,7 @@ class Capabilities { } areDefined() { - return this._has_caps; + return this._hasCaps; } has(name) { @@ -102,6 +113,10 @@ class Capabilities { get length() { return this._capabilities.size; } + + featureEnabled(feature) { + return this._featuresEnabled[feature.toUpperCase()] == true; + } } export default Capabilities; diff --git a/src/gmp/commands/__tests__/user.js b/src/gmp/commands/__tests__/user.js index 17fe9d1ec9..fe39552f46 100644 --- a/src/gmp/commands/__tests__/user.js +++ b/src/gmp/commands/__tests__/user.js @@ -121,3 +121,58 @@ describe('UserCommand transformSettingName() function tests', () => { expect(transformSettingName(str4)).toEqual('foobar'); }); }); + +describe('UserCommand capabilities tests', () => { + test('should get capabilities', () => { + const response = createResponse({ + get_capabilities: { + help_response: { + schema: { + command: [ + { + name: 'get_reports', + }, + { + name: 'get_tasks', + }, + ], + }, + }, + get_features_response: { + feature: [ + { + _enabled: 1, + name: 'TEST_FEATURE_1', + }, + { + _enabled: 1, + name: 'TEST_FEATURE_2', + }, + ], + }, + }, + }); + const fakeHttp = createHttp(response); + const cmd = new UserCommand(fakeHttp); + + cmd.currentCapabilities().then(resp => { + const {data: caps} = resp; + + expect(fakeHttp.request).toHaveBeenCalledWith('get', { + args: { + cmd: 'get_capabilities', + }, + }); + + expect(caps._hasCaps).toBe(true); + expect(caps.mayAccess('report')).toBe(true); + expect(caps.mayAccess('task')).toBe(true); + expect(caps.mayAccess('user')).toBe(false); + + expect(caps._hasFeatures).toBe(true); + expect(caps.featureEnabled('test_feature_1')).toBe(true); + expect(caps.featureEnabled('TEST_FEATURE_2')).toBe(true); + expect(caps.featureEnabled('TEST_FEATURE_3')).toBe(false); + }); + }); +}); diff --git a/src/gmp/commands/users.js b/src/gmp/commands/users.js index 65dcc9ab98..c94c4077e7 100644 --- a/src/gmp/commands/users.js +++ b/src/gmp/commands/users.js @@ -162,8 +162,9 @@ export class UserCommand extends EntityCommand { ).then(response => { const {data} = response; const {command: commands} = data.get_capabilities.help_response.schema; + const featuresList = data.get_capabilities.get_features_response.feature; const caps = map(commands, command => command.name); - return response.setData(new Capabilities(caps)); + return response.setData(new Capabilities(caps, featuresList)); }); }