import { StoreParties , StoreDocs , DocumentSsh , Document } from './stores' ; import Logger from 'shared/libs/logger' ; import session from 'teleport/services/session' ; import history from 'teleport/services/history' ; import cfg , { UrlSshParams } from 'teleport/config' ; import { getAccessToken , getHostName } from 'teleport/services/api' ; import Tty from 'teleport/lib/term/tty' ; import TtyAddressResolver from 'teleport/lib/term/ttyAddressResolver' ; import serviceSsh , { Session , ParticipantList } from 'teleport/services/ssh' ; import serviceNodes from 'teleport/services/nodes' ; import serviceClusters from 'teleport/services/clusters' ; import serviceUser from 'teleport/services/user' ; const logger = Logger . create ( 'teleport/console' ) ; /**
 * Console Context is used by components to access shared state and also to communicate
 * with other services.
 */ export default class ConsoleContext { storeDocs = new StoreDocs ( ) ; storeParties = new StoreParties ( ) ; constructor ( ) { this . storeDocs . add ( { kind : 'blank' , url : cfg . getConsoleRoute ( cfg . proxyCluster ) , clusterId : cfg . proxyCluster , created : new Date ( ) , } ) ; } getActiveDocId ( url ) { const doc = this . storeDocs . findByUrl ( url ) ; return doc ? doc . id : - 1 ; } removeDocument ( id ) { const nextId = this . storeDocs . getNext ( id ) ; const items = this . storeDocs . filter ( id ) ; this . storeDocs . setState ( { items } ) ; return this . storeDocs . find ( nextId ) ; } updateSshDocument ( id , partial ) { this . storeDocs . update ( id , partial ) ; } addNodeDocument ( clusterId = cfg . proxyCluster ) { return this . storeDocs . add ( { clusterId , title : `New session` , kind : 'nodes' , url : cfg . getConsoleNodesRoute ( clusterId ) , created : new Date ( ) , } ) ; } addSshDocument ( { login , serverId , sid , clusterId } ) { const title = login && serverId ? `${ login }@${ serverId }` : sid ; const url = this . getSshDocumentUrl ( { clusterId , login , serverId , sid , } ) ; return this . storeDocs . add ( { kind : 'terminal' , status : 'disconnected' , clusterId , title , serverId , login , sid , url , created : new Date ( ) , } ) ; } getDocuments ( ) { return this . storeDocs . state . items ; } getNodeDocumentUrl ( clusterId ) { return cfg . getConsoleNodesRoute ( clusterId ) ; } getSshDocumentUrl ( sshParams ) { return sshParams . sid ? cfg . getSshSessionRoute ( sshParams ) : cfg . getSshConnectRoute ( sshParams ) ; } refreshParties ( ) { const clusters = this . storeDocs . getSshDocuments ( ) . filter ( doc => doc . status === 'connected' ) . map ( doc => doc . clusterId ) ; const unique = [ ... new Set ( clusters ) ] ; const requests = unique . map ( clusterId => serviceSsh . fetchParticipants ( { clusterId } ) . catch ( err => { logger . error ( 'failed to refresh participants' , err ) ; const emptyResults = { } ; return emptyResults ; } ) ) ; return Promise . all ( requests ) . then ( results => { let parties = { } ; for ( let i = 0 ; i < results . length ; i ++ ) { parties = { ... results [ i ] , } ; } this . storeParties . setParties ( parties ) ; } ) ; } fetchNodes ( clusterId ) { return Promise . all ( [ serviceUser . fetchUserContext ( ) , serviceNodes . fetchNodes ( clusterId ) , ] ) . then ( values => { const [ user , nodes ] = values ; return { logins : user . acl . sshLogins , nodes , } ; } ) ; } fetchClusters ( ) { return serviceClusters . fetchClusters ( ) ; } fetchSshSession ( clusterId , sid ) { return serviceSsh . fetchSession ( { clusterId , sid } ) ; } createSshSession ( clusterId , serverId , login ) { return serviceSsh . create ( { serverId , clusterId , login , } ) ; } logout ( ) { session . logout ( ) ; } createTty ( session ) { const { login , sid , serverId , clusterId } = session ; const ttyUrl = cfg . api . ttyWsAddr . replace ( ':fqdm' , getHostName ( ) ) . replace ( ':token' , getAccessToken ( ) ) . replace ( ':clusterId' , clusterId ) ; const addressResolver = new TtyAddressResolver ( { ttyUrl , ttyParams : { login , sid , server_id : serverId , } , } ) ; return new Tty ( addressResolver ) ; } gotoNodeTab ( clusterId ) { const url = this . getNodeDocumentUrl ( clusterId ) ; this . gotoTab ( { url } ) ; } gotoTab ( { url } , replace = true ) { if ( replace ) { history . replace ( url ) ; } else { history . push ( url ) ; } } closeTab ( doc ) { const next = this . removeDocument ( doc . id ) ; this . gotoTab ( next ) ; } }