import { Plugin , CoreStart , CoreSetup , HttpStart , PluginInitializerContext , SavedObjectsClientContract , SavedObjectsBatchResponse , ApplicationStart , } from '../../../core/public' ; import { TelemetrySender , TelemetryService , TelemetryNotifications } from './services' ; import { TelemetrySavedObjectAttributes , TelemetrySavedObject , } from '../common/telemetry_config/types' ; import { getTelemetryAllowChangingOptInStatus , getTelemetryOptIn , getTelemetrySendUsageFrom , } from '../common/telemetry_config' ; import { getNotifyUserAboutOptInDefault } from '../common/telemetry_config/get_telemetry_notify_user_about_optin_default' ; import { PRIVACY_STATEMENT_URL } from '../common/constants' ; export interface TelemetryPluginSetup { telemetryService : TelemetryService ; } export interface TelemetryPluginStart { telemetryService : TelemetryService ; telemetryNotifications : TelemetryNotifications ; telemetryConstants : { getPrivacyStatementUrl : ( ) => string ; } ; } export interface TelemetryPluginConfig { enabled : boolean ; url : string ; banner : boolean ; allowChangingOptInStatus : boolean ; optIn : boolean | null ; optInStatusUrl : string ; sendUsageFrom : 'browser' | 'server' ; telemetryNotifyUserAboutOptInDefault ? : boolean ; userCanChangeSettings ? : boolean ; } export class TelemetryPlugin implements Plugin < TelemetryPluginSetup , TelemetryPluginStart > { private readonly currentOpenSearchDashboardsVersion : string ; private readonly config : TelemetryPluginConfig ; private telemetrySender ? : TelemetrySender ; private telemetryNotifications ? : TelemetryNotifications ; private telemetryService ? : TelemetryService ; private canUserChangeSettings : boolean = true ; constructor ( initializerContext ) { this . currentOpenSearchDashboardsVersion = initializerContext . env . packageInfo . version ; this . config = initializerContext . config . get ( ) ; } public setup ( { http , notifications } ) { const config = this . config ; this . telemetryService = new TelemetryService ( { config , http , notifications } ) ; this . telemetrySender = new TelemetrySender ( this . telemetryService ) ; return { telemetryService : this . telemetryService , } ; } public start ( { http , overlays , application , savedObjects } ) { if ( ! this . telemetryService ) { throw Error ( 'Telemetry plugin failed to initialize properly.' ) ; } this . canUserChangeSettings = this . getCanUserChangeSettings ( application ) ; this . telemetryService . userCanChangeSettings = this . canUserChangeSettings ; this . telemetryNotifications = new TelemetryNotifications ( { overlays , telemetryService : this . telemetryService , } ) ; application . currentAppId$ . subscribe ( async ( ) => { const isUnauthenticated = this . getIsUnauthenticated ( http ) ; if ( isUnauthenticated ) { return ; } const telemetrySavedObject = await this . getTelemetrySavedObject ( savedObjects . client ) ; const updatedConfig = await this . updateConfigsBasedOnSavedObjects ( telemetrySavedObject ) ; this . telemetryService ! . config = updatedConfig ; const telemetryBanner = updatedConfig . banner ; this . maybeStartTelemetryPoller ( ) ; if ( telemetryBanner ) { this . maybeShowOptedInNotificationBanner ( ) ; this . maybeShowOptInBanner ( ) ; } } ) ; return { telemetryService : this . telemetryService , telemetryNotifications : this . telemetryNotifications , telemetryConstants : { getPrivacyStatementUrl : ( ) => PRIVACY_STATEMENT_URL , } , } ; } param application private private getCanUserChangeSettings ( application ) { return ( application . capabilities ?. savedObjectsManagement ?. edit as boolean | undefined ) ?? true ; } private getIsUnauthenticated ( http ) { const { anonymousPaths } = http ; return anonymousPaths . isAnonymous ( window . location . pathname ) ; } private maybeStartTelemetryPoller ( ) { if ( ! this . telemetrySender ) { return ; } this . telemetrySender . startChecking ( ) ; } private maybeShowOptedInNotificationBanner ( ) { if ( ! this . telemetryNotifications ) { return ; } const shouldShowBanner = this . telemetryNotifications . shouldShowOptedInNoticeBanner ( ) ; if ( shouldShowBanner ) { this . telemetryNotifications . renderOptedInNoticeBanner ( ) ; } } private maybeShowOptInBanner ( ) { if ( ! this . telemetryNotifications ) { return ; } const shouldShowBanner = this . telemetryNotifications . shouldShowOptInBanner ( ) ; if ( shouldShowBanner ) { this . telemetryNotifications . renderOptInBanner ( ) ; } } private async updateConfigsBasedOnSavedObjects ( telemetrySavedObject ) { const configTelemetrySendUsageFrom = this . config . sendUsageFrom ; const configTelemetryOptIn = this . config . optIn as boolean ; const configTelemetryAllowChangingOptInStatus = this . config . allowChangingOptInStatus ; const currentOpenSearchDashboardsVersion = this . currentOpenSearchDashboardsVersion ; const allowChangingOptInStatus = getTelemetryAllowChangingOptInStatus ( { configTelemetryAllowChangingOptInStatus , telemetrySavedObject , } ) ; const optIn = getTelemetryOptIn ( { configTelemetryOptIn , allowChangingOptInStatus , telemetrySavedObject , currentOpenSearchDashboardsVersion , } ) ; const sendUsageFrom = getTelemetrySendUsageFrom ( { configTelemetrySendUsageFrom , telemetrySavedObject , } ) ; const telemetryNotifyUserAboutOptInDefault = getNotifyUserAboutOptInDefault ( { telemetrySavedObject , allowChangingOptInStatus , configTelemetryOptIn , telemetryOptedIn : optIn , } ) ; return { ... this . config , optIn , sendUsageFrom , telemetryNotifyUserAboutOptInDefault , userCanChangeSettings : this . canUserChangeSettings , } ; } private async getTelemetrySavedObject ( savedObjectsClient ) { try { const { savedObjects : [ { attributes } ] , } = ( await savedObjectsClient . bulkGet ( [ { id : 'telemetry' , type : 'telemetry' , } , ] ) ) as SavedObjectsBatchResponse < TelemetrySavedObjectAttributes > ; return attributes ; } catch ( error ) { const errorCode = error [ Symbol ( 'SavedObjectsClientErrorCode' ) ] ; if ( errorCode === 'SavedObjectsClient/notFound' ) { return null ; } if ( errorCode === 'SavedObjectsClient/forbidden' ) { return false ; } throw error ; } } }