import _ from 'lodash' ; import type { Capabilities , CapabilitiesSwitcher , CoreSetup , Logger } from 'src/core/server' ; import type { KibanaFeature } from '../../../features/server' ; import type { Space } from '../../common' ; import type { PluginsStart } from '../plugin' ; import type { SpacesServiceStart } from '../spaces_service' ; export function setupCapabilitiesSwitcher ( core , getSpacesService , logger ) { return async ( request , capabilities , useDefaultCapabilities ) => { const isAuthRequiredOrOptional = ! request . route . options . authRequired ; const shouldNotToggleCapabilities = isAuthRequiredOrOptional || useDefaultCapabilities ; if ( shouldNotToggleCapabilities ) { return capabilities ; } try { const [ activeSpace , [ , { features } ] ] = await Promise . all ( [ getSpacesService ( ) . getActiveSpace ( request ) , core . getStartServices ( ) , ] ) ; const registeredFeatures = features . getKibanaFeatures ( ) ; return toggleCapabilities ( registeredFeatures , capabilities , activeSpace ) ; } catch ( e ) { logger . debug ( `Error toggling capabilities for request to ${ request . url . pathname }: ${ e }` ) ; return capabilities ; } } ; } function toggleCapabilities ( features , capabilities , activeSpace ) { const clonedCapabilities = _ . cloneDeep ( capabilities ) ; toggleDisabledFeatures ( features , clonedCapabilities , activeSpace ) ; return clonedCapabilities ; } function toggleDisabledFeatures ( features , capabilities , activeSpace ) { const disabledFeatureKeys = activeSpace . disabledFeatures ; const [ enabledFeatures , disabledFeatures ] = features . reduce ( ( acc , feature ) => { if ( disabledFeatureKeys . includes ( feature . id ) ) { return [ acc [ 0 ] , [ ... acc [ 1 ] , feature ] ] ; } return [ [ ... acc [ 0 ] , feature ] , acc [ 1 ] ] ; } , [ [ ] , [ ] ] as [ KibanaFeature [ ] , KibanaFeature [ ] ] ) ; const navLinks = capabilities . navLinks ; const catalogueEntries = capabilities . catalogue ; const managementItems = capabilities . management ; const enabledAppEntries = new Set ( enabledFeatures . flatMap ( ( ef ) => ef . app ?? [ ] ) ) ; const enabledCatalogueEntries = new Set ( enabledFeatures . flatMap ( ( ef ) => ef . catalogue ?? [ ] ) ) ; const enabledManagementEntries = enabledFeatures . reduce ( ( acc , feature ) => { const sections = Object . entries ( feature . management ?? { } ) ; sections . forEach ( ( section ) => { if ( ! acc . has ( section [ 0 ] ) ) { acc . set ( section [ 0 ] , [ ] ) ; } acc . get ( section [ 0 ] ) ! . push ( ... section [ 1 ] ) ; } ) ; return acc ; } , new Map < string , string [ ] > ( ) ) ; for ( const feature of disabledFeatures ) { feature . app . forEach ( ( app ) => { if ( navLinks . hasOwnProperty ( app ) && ! enabledAppEntries . has ( app ) ) { navLinks [ app ] = false ; } } ) ; const privilegeCatalogueEntries = feature . catalogue || [ ] ; privilegeCatalogueEntries . forEach ( ( catalogueEntryId ) => { if ( ! enabledCatalogueEntries . has ( catalogueEntryId ) ) { catalogueEntries [ catalogueEntryId ] = false ; } } ) ; const privilegeManagementSections = feature . management || { } ; Object . entries ( privilegeManagementSections ) . forEach ( ( [ sectionId , sectionItems ] ) => { sectionItems . forEach ( ( item ) => { const enabledManagementEntriesSection = enabledManagementEntries . get ( sectionId ) ; if ( managementItems . hasOwnProperty ( sectionId ) && managementItems [ sectionId ] . hasOwnProperty ( item ) ) { const isEnabledElsewhere = ( enabledManagementEntriesSection ?? [ ] ) . includes ( item ) ; if ( ! isEnabledElsewhere ) { managementItems [ sectionId ] [ item ] = false ; } } } ) ; } ) ; if ( capabilities . hasOwnProperty ( feature . id ) ) { const capability = capabilities [ feature . id ] ; Object . keys ( capability ) . forEach ( ( featureKey ) => { capability [ featureKey ] = false ; } ) ; } } }