File

projects/netgrif-components-core/src/lib/authentication/session/services/session.service.ts

Index

Properties
Methods
Accessors

Constructor

constructor(_config: ConfigurationService, _log: LoggerService, _http: HttpClient, idleTimerService: SessionIdleTimerService)
Parameters :
Name Type Optional
_config ConfigurationService No
_log LoggerService No
_http HttpClient No
idleTimerService SessionIdleTimerService No

Methods

Public clear
clear()
Returns : void
Protected load
load()
Returns : string
ngOnDestroy
ngOnDestroy()
Returns : void
Public setVerifiedToken
setVerifiedToken(sessionToken: string)
Parameters :
Name Type Optional
sessionToken string No
Returns : void
Public verify
verify(token?: string)
Parameters :
Name Type Optional
token string Yes
Returns : Observable<boolean>

Properties

Static Readonly SESSION_BEARER_HEADER_DEFAULT
Type : string
Default value : 'X-Auth-Token'
Static Readonly SESSION_TOKEN_STORAGE_KEY
Type : string
Default value : 'naet'

Accessors

session$
getsession$()
sessionToken
getsessionToken()
setsessionToken(sessionToken: string)
Parameters :
Name Type Optional
sessionToken string No
Returns : void
sessionHeader
getsessionHeader()
verified
getverified()
verifying
getverifying()
isVerifying
getisVerifying()
isInitialized
getisInitialized()
initializing
getinitializing()
import {Injectable, OnDestroy} from '@angular/core';
import {BehaviorSubject, Observable, throwError} from 'rxjs';
import {ConfigurationService} from '../../../configuration/configuration.service';
import {NullStorage} from '../null-storage';
import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
import {LoggerService} from '../../../logger/services/logger.service';
import {catchError, map, take, tap} from 'rxjs/operators';
import {MessageResource} from '../../../resources/interface/message-resource';
import {LoadingEmitter} from '../../../utility/loading-emitter';
import {SessionIdleTimerService} from "./session-idle-timer.service";


@Injectable({
    providedIn: 'root'
})
export class SessionService implements OnDestroy {

    public static readonly SESSION_TOKEN_STORAGE_KEY = 'naet';
    public static readonly SESSION_BEARER_HEADER_DEFAULT = 'X-Auth-Token';

    private _session$: BehaviorSubject<string>;
    private _storage: Storage;
    private readonly _sessionHeader: string;
    private _verified: boolean;
    private _verifying: LoadingEmitter;
    private _initialized: LoadingEmitter;

    constructor(private _config: ConfigurationService,
                private _log: LoggerService,
                private _http: HttpClient,
                private idleTimerService: SessionIdleTimerService) {
        this._storage = this.resolveStorage(this._config.get().providers.auth['sessionStore']);
        this._sessionHeader = this._config.get().providers.auth.sessionBearer ?
            this._config.get().providers.auth.sessionBearer : SessionService.SESSION_BEARER_HEADER_DEFAULT;
        this._session$ = new BehaviorSubject<string>(null);
        this._verified = false;
        this.idleTimerService.stopTimer()
        this._verifying = new LoadingEmitter();
        this._initialized = new LoadingEmitter(false);
        setTimeout(() => {
            this.load();
        });
    }

    ngOnDestroy(): void {
        this._session$.complete();
        this._verifying.complete();
    }

    get session$(): Observable<string> {
        return this._session$.asObservable();
    }

    set sessionToken(sessionToken: string) {
        this._session$.next(sessionToken);
        this._storage.setItem(SessionService.SESSION_TOKEN_STORAGE_KEY,
            btoa(SessionService.SESSION_TOKEN_STORAGE_KEY + ':' + sessionToken));
    }

    get sessionToken(): string {
        return this._session$.getValue();
    }

    get sessionHeader(): string {
        return this._sessionHeader;
    }

    get verified(): boolean {
        return this._verified;
    }

    get verifying(): Observable<boolean> {
        return this._verifying.asObservable();
    }

    get isVerifying(): boolean {
        return this._verifying.isActive;
    }

    get isInitialized(): boolean {
        return this._initialized.isActive;
    }

    get initializing(): Observable<boolean> {
        return this._initialized.asObservable();
    }

    public setVerifiedToken(sessionToken: string) {
        this._log.warn('Session token without explicit verification was set');
        this.idleTimerService.resetTimer()
        this._verified = true;
        this.sessionToken = sessionToken;
    }

    public clear(): void {
        this.idleTimerService.stopTimer()
        this._verified = false;
        this.sessionToken = '';
        this._storage.removeItem(SessionService.SESSION_TOKEN_STORAGE_KEY);
    }

    public verify(token?: string): Observable<boolean> {
        this._verifying.on();
        token = !!token ? token : this.sessionToken;

        const authConfig = this._config.get().providers.auth;
        let url = authConfig.address;
        url += authConfig.endpoints && authConfig.endpoints['verification'] ? authConfig.endpoints['verification'] :
            (authConfig.endpoints && authConfig.endpoints['login'] ? authConfig.endpoints['login'] : '');
        if (!url || url === authConfig.address) {
            this.clear();
            this._verifying.off();
            this._initialized.on();
            return throwError(new Error('Cannot verify session token. ' +
                'Login URL is not defined in the config [nae.providers.auth.endpoints.login].'));
        } else {
            return this._http.get<MessageResource>(url, {
                headers: new HttpHeaders().set(this._sessionHeader, token),
                observe: 'response'
            }).pipe(
                catchError(error => {
                    if (error instanceof HttpErrorResponse && error.status === 401) {
                        this._log.warn('Authentication token is invalid. Clearing session token');
                        this.clear();
                    }
                    this._verifying.off();
                    this.idleTimerService.stopTimer()
                    this._initialized.on();
                    return throwError(error);
                }),
                map(response => {
                    this._log.debug(response.body.success);
                    this._verified = true;
                    this.idleTimerService.resetTimer()
                    this._initialized.on();
                    this.sessionToken = token;
                    return true;
                }),
                tap(_ => this._verifying.off())
            );
        }
    }

    protected load(): string {
        let token = this._storage.getItem(SessionService.SESSION_TOKEN_STORAGE_KEY);
        this._verified = false;
        this.idleTimerService.stopTimer()
        if (token) {
            token = this.resolveToken(token);
            this.sessionToken = token;
            this.verify(token).pipe(take(1)).subscribe(ver => {
                this._log.debug('Token ' + token + ' verified status: ' + ver);
            });
        } else {
            this._initialized.on();
        }
        return '';
    }

    private resolveToken(raw: string): string {
        return raw ? atob(raw).split(':')[1] : '';
    }

    private resolveStorage(storage: string): any {
        switch (storage) {
            case 'local':
                return localStorage;
            case 'session':
                return sessionStorage;
            case 'null':
                return new NullStorage();
            default:
                return localStorage;
        }
    }
}

result-matching ""

    No results matching ""