/********************************************************************************
 * Copyright (C) 2020 Red Hat, Inc. and others.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the Eclipse
 * Public License v. 2.0 are satisfied: GNU General Public License, version 2
 * with the GNU Classpath Exception which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 ********************************************************************************/ import { Disposable } from './types-impl' ; import { AuthenticationExt , AuthenticationMain , Plugin as InternalPlugin , PLUGIN_RPC_CONTEXT } from '../common/plugin-api-rpc' ; import { RPCProtocol } from '../common/rpc-protocol' ; import { Emitter , Event } from '@theia/core/lib/common/event' ; import * as theia from '@theia/plugin' ; import { AuthenticationSession , AuthenticationSessionsChangeEvent } from '../common/plugin-api-rpc-model' ; export class AuthenticationExtImpl implements AuthenticationExt { private proxy : AuthenticationMain ; private authenticationProviders : Map < string , theia . AuthenticationProvider > = new Map < string , theia . AuthenticationProvider > ( ) ; private _providerIds : string [ ] = [ ] ; private _providers : theia . AuthenticationProviderInformation [ ] = [ ] ; private onDidChangeAuthenticationProvidersEmitter = new Emitter < theia . AuthenticationProvidersChangeEvent > ( ) ; readonly onDidChangeAuthenticationProviders : Event < theia . AuthenticationProvidersChangeEvent > = this . onDidChangeAuthenticationProvidersEmitter . event ; private onDidChangeSessionsEmitter = new Emitter < theia . AuthenticationSessionsChangeEvent > ( ) ; readonly onDidChangeSessions : Event < theia . AuthenticationSessionsChangeEvent > = this . onDidChangeSessionsEmitter . event ; constructor ( rpc ) { this . proxy = rpc . getProxy ( PLUGIN_RPC_CONTEXT . AUTHENTICATION_MAIN ) ; } getProviderIds ( ) { return this . proxy . $getProviderIds ( ) ; } get providerIds ( ) : string [ ] { return this . _providerIds ; } get providers ( ) : ReadonlyArray < theia . AuthenticationProviderInformation > { return Object . freeze ( this . _providers . slice ( ) ) ; } async getSession ( requestingExtension , providerId , scopes , options ) ; async getSession ( requestingExtension , providerId , scopes , options = { } ) { const extensionName = requestingExtension . model . displayName || requestingExtension . model . name ; const extensionId = requestingExtension . model . id . toLowerCase ( ) ; return this . proxy . $getSession ( providerId , scopes , extensionId , extensionName , options ) ; } async logout ( providerId , sessionId ) { return this . proxy . $logout ( providerId , sessionId ) ; } registerAuthenticationProvider ( provider ) { if ( this . authenticationProviders . get ( provider . id ) ) { throw new Error ( `An authentication provider with id '${ provider . id }' is already registered.` ) ; } this . authenticationProviders . set ( provider . id , provider ) ; if ( this . _providerIds . indexOf ( provider . id ) === - 1 ) { this . _providerIds . push ( provider . id ) ; } if ( ! this . _providers . find ( p => p . id === provider . id ) ) { this . _providers . push ( { id : provider . id , label : provider . label } ) ; } const listener = provider . onDidChangeSessions ( e => { this . proxy . $updateSessions ( provider . id , e ) ; } ) ; this . proxy . $registerAuthenticationProvider ( provider . id , provider . label , provider . supportsMultipleAccounts ) ; return new Disposable ( ( ) => { listener . dispose ( ) ; this . authenticationProviders . delete ( provider . id ) ; const index = this . _providerIds . findIndex ( id => id === provider . id ) ; if ( index > - 1 ) { this . _providerIds . splice ( index ) ; } const i = this . _providers . findIndex ( p => p . id === provider . id ) ; if ( i > - 1 ) { this . _providers . splice ( i ) ; } this . proxy . $unregisterAuthenticationProvider ( provider . id ) ; } ) ; } $login ( providerId , scopes ) { const authProvider = this . authenticationProviders . get ( providerId ) ; if ( authProvider ) { return Promise . resolve ( authProvider . login ( scopes ) ) ; } throw new Error ( `Unable to find authentication provider with handle: ${ providerId }` ) ; } $logout ( providerId , sessionId ) { const authProvider = this . authenticationProviders . get ( providerId ) ; if ( authProvider ) { return Promise . resolve ( authProvider . logout ( sessionId ) ) ; } throw new Error ( `Unable to find authentication provider with handle: ${ providerId }` ) ; } async $getSessions ( providerId ) { const authProvider = this . authenticationProviders . get ( providerId ) ; if ( authProvider ) { const sessions = await authProvider . getSessions ( ) ; return sessions . map ( session => ( { id : session . id , accessToken : session . accessToken , account : { id : session . account . id , label : session . account . label } , scopes : session . scopes } ) ) ; } throw new Error ( `Unable to find authentication provider with handle: ${ providerId }` ) ; } $onDidChangeAuthenticationSessions ( id , label , event ) { this . onDidChangeSessionsEmitter . fire ( { provider : { id , label } , ... event } ) ; return Promise . resolve ( ) ; } async $onDidChangeAuthenticationProviders ( added , removed ) { added . forEach ( id => { if ( this . _providers . indexOf ( id ) === - 1 ) { this . _providers . push ( id ) ; } } ) ; removed . forEach ( p => { const index = this . _providers . findIndex ( provider => provider . id === p . id ) ; if ( index > - 1 ) { this . _providers . splice ( index ) ; } } ) ; this . onDidChangeAuthenticationProvidersEmitter . fire ( { added , removed } ) ; } }