import Logger from 'shared/libs/logger' ; import cfg from 'teleport/config' ; import history from 'teleport/services/history' ; import api from 'teleport/services/api' ; import localStorage , { KeysEnum } from 'teleport/services/localStorage' ; import makeBearerToken from './makeBearerToken' ; import { RenewSessionRequest } from './types' ; const RENEW_TOKEN_TIME = 180 * 1000 ; const TOKEN_CHECKER_INTERVAL = 15 * 1000 ; const logger = Logger . create ( 'services/session' ) ; let sesstionCheckerTimerId = null ; const session = { logout ( ) { api . delete ( cfg . api . sessionPath ) . finally ( ( ) => { history . goToLogin ( ) ; } ) ; this . clear ( ) ; } , clear ( ) { this . _stopTokenChecker ( ) ; localStorage . unsubscribe ( receiveMessage ) ; localStorage . clear ( ) ; } , ensureSession ( ) { this . _stopTokenChecker ( ) ; this . _ensureLocalStorageSubscription ( ) ; if ( ! this . isValid ( ) ) { this . logout ( ) ; return ; } if ( this . _shouldRenewToken ( ) ) { this . _renewToken ( ) . then ( ( ) => { this . _startTokenChecker ( ) ; } ) . catch ( this . logout . bind ( this ) ) ; } else { this . _startTokenChecker ( ) ; } } , renewSession ( req ) { return this . _renewToken ( req ) . then ( token => token . sessionExpires ) ; } , isValid ( ) { return this . _timeLeft ( ) > 0 ; } , getInactivityTimeout ( ) { const bearerToken = this . _getBearerToken ( ) ; const time = Number ( bearerToken . sessionInactiveTimeout ) ; return time ? time : 0 ; } , _getBearerToken ( ) { let token = null ; try { token = this . _extractBearerTokenFromHtml ( ) ; if ( token ) { localStorage . setBearerToken ( token ) ; } else { token = localStorage . getBearerToken ( ) ; } } catch ( err ) { logger . error ( 'Cannot find bearer token' , err ) ; } return token ; } , _extractBearerTokenFromHtml ( ) { const el = document . querySelector < HTMLMetaElement > ( '[name=grv_bearer_token]' ) ; if ( ! el || ! el . content ) { return null ; } el . parentNode . removeChild ( el ) ; const decoded = window . atob ( el . content ) ; const json = JSON . parse ( decoded ) ; return makeBearerToken ( json ) ; } , _shouldRenewToken ( ) { if ( this . _getIsRenewing ( ) ) { return false ; } return this . _timeLeft ( ) < RENEW_TOKEN_TIME ; } , _renewToken ( req = { } ) { this . _setAndBroadcastIsRenewing ( true ) ; return api . post ( cfg . getRenewTokenUrl ( ) , req ) . then ( json => { const token = makeBearerToken ( json ) ; localStorage . setBearerToken ( token ) ; return token ; } ) . finally ( ( ) => { this . _setAndBroadcastIsRenewing ( false ) ; } ) ; } , _setAndBroadcastIsRenewing ( value ) { this . _setIsRenewing ( value ) ; localStorage . broadcast ( KeysEnum . TOKEN_RENEW , value ) ; } , _setIsRenewing ( value ) { this . _isRenewing = value ; } , _getIsRenewing ( ) { return ! ! this . _isRenewing ; } , _timeLeft ( ) { const token = this . _getBearerToken ( ) ; if ( ! token ) { return 0 ; } let { expiresIn , created } = token ; if ( ! created || ! expiresIn ) { return 0 ; } expiresIn = expiresIn * 1000 ; const delta = created + expiresIn - new Date ( ) . getTime ( ) ; return delta ; } , _shouldCheckStatus ( ) { if ( this . _getIsRenewing ( ) ) { return false ; } return this . _timeLeft ( ) > TOKEN_CHECKER_INTERVAL * 2 ; } , _ensureLocalStorageSubscription ( ) { localStorage . subscribe ( receiveMessage ) ; } , _fetchStatus ( ) { api . get ( cfg . api . userStatusPath ) . catch ( err => { if ( err . response . status == 403 ) { this . logout ( ) ; } } ) ; } , _startTokenChecker ( ) { this . _stopTokenChecker ( ) ; sesstionCheckerTimerId = setInterval ( ( ) => { this . ensureSession ( ) ; if ( this . _shouldCheckStatus ( ) ) { this . _fetchStatus ( ) ; } } , TOKEN_CHECKER_INTERVAL ) ; } , _stopTokenChecker ( ) { clearInterval ( sesstionCheckerTimerId ) ; sesstionCheckerTimerId = null ; } , } ; function receiveMessage ( event ) { const { key , newValue } = event ; if ( localStorage . getBearerToken ( ) === null ) { session . logout ( ) ; } if ( key === KeysEnum . TOKEN_RENEW && ! ! newValue ) { session . _setIsRenewing ( JSON . parse ( newValue ) ) ; } } export default session ;