/** @file * @author Edouard DUPIN * @copyright 2018, Edouard DUPIN, all right reserved * @license PROPRIETARY (see license file) */ import { Inject, Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { StorageService } from '../service/local-storage'; import { SessionService } from './session'; import { SSOService } from './sso'; import { getApplicationLocation, isNullOrUndefined, sha512 } from '../utils'; import { HttpWrapperService, HTTPRequestModel, HTTPMimeType, ModelResponseHttp } from './http-wrapper_kjdhqslkjf'; import { Environment } from '../model/environment'; import { APP_BASE_HREF } from '@angular/common'; @Injectable() export class UserService { // 0: Not hide password; 1 hide password; private identificationVersion: number = 1; private cookiesRememberMe = 'remember-me'; private cookiesToken = 'token'; constructor( @Inject('ENVIRONMENT') private environment: Environment, private router: Router, private storageService: StorageService, private http: HttpWrapperService, private sessionService: SessionService, private ssoService: SSOService ) { console.log('Start UserService'); } /** * Disconnect the user from the current session ==> this remove the current Token */ logOut(): void { this.removeSession(); this.ssoService.requestSignOut('home'); } removeSession(): void { this.storageService.remove(this.cookiesRememberMe); this.storageService.removeSession(this.cookiesToken); this.storageService.remove(this.cookiesToken); this.sessionService.destroy(); } private isTokenUpToDate(token?: string): boolean { if (isNullOrUndefined(token) || token.length < 25) { return false; } // Separate the Data: const elems = token.split('.'); if (elems.length !== 3) { return false; } // const tokenHeader = decodeURIComponent(window.atob( elems[0] )); const tokenData = decodeURIComponent(window.atob(elems[1])); // console.error(`Retrieve local token: \nheader=${tokenHeader} \ndata=${tokenData}`); const parsedData = JSON.parse(tokenData); console.debug( `Retrieve token exp data=${new Date(parsedData.exp * 1000).toISOString()} < ${new Date().toISOString()}` ); const expireIn = new Date(parsedData.exp * 1000); const nowTime = new Date(); // TODO: set a margin of 2 hours... return expireIn > nowTime; } getRememberMe(): boolean { return this.storageService.get(this.cookiesRememberMe) === 'true'; } /** * Check if the system can be connected */ checkAutoConnect(): Promise { let locationOrigin = getApplicationLocation(this.environment); const self = this; return new Promise((resolve, reject) => { // Need to use the windows global route to prevent the log in cycle ... // And in the main application position, the route does not have currently root the page let pathName = window.location.pathname; // console.log("start Path-name: '" + pathName + "'"); // console.log("check with: '" + environment.applName + "/sso/" + "'"); if (pathName.startsWith('/sso/') || pathName.startsWith(this.environment.applName + '/sso/')) { console.log(' ==> SSo section'); reject(); return; } console.log(' ==> Check if need reconnect?'); let rememberMe = self.getRememberMe(); // TODO: in case of jest reload ==> no need to manage the SSO ==> just keep the token ... it in enough... let token: undefined | string = undefined; if ( isNullOrUndefined(this.environment.tokenStoredInPermanentStorage) || this.environment.tokenStoredInPermanentStorage !== true ) { token = self.storageService.getSession(self.cookiesToken); } else { token = self.storageService.get(self.cookiesToken); } // TODO: check validity of the Token: if (self.isTokenUpToDate(token)) { // remove in case of fail !!! this.storageService.removeSession(this.cookiesToken); this.storageService.remove(this.cookiesToken); self.startSession(token ?? '', rememberMe) .then(() => { self.router.navigateByUrl(locationOrigin); console.log(`update global URL = ${locationOrigin} APP_BASE_HREF=${APP_BASE_HREF}`); resolve(); }) .catch(() => { // jump in the sign-in page (automatically of request remember-me) if (rememberMe) { // jump to the sso !!! (remove local data to prevent login loop) this.storageService.remove(this.cookiesRememberMe); this.storageService.remove(this.cookiesToken); this.storageService.removeSession(this.cookiesToken); self.ssoService.requestSignIn(locationOrigin); reject(); } resolve(); }); } else { console.log(`Get previous connection ... `); if (rememberMe) { // jump to the sso !!! (remove local data to prevent login loop) this.storageService.remove(this.cookiesRememberMe); this.storageService.remove(this.cookiesToken); this.storageService.removeSession(this.cookiesToken); self.ssoService.requestSignIn(locationOrigin); reject(); } resolve(); } }); } startSession(token: string, rememberMe: boolean): Promise { const self = this; return new Promise((resolve, reject) => { self.retrieveMe(token) .then((value2: boolean) => { if (rememberMe === true) { self.storageService.set(self.cookiesRememberMe, rememberMe ? 'true' : 'false'); } if ( isNullOrUndefined(this.environment.tokenStoredInPermanentStorage) || this.environment.tokenStoredInPermanentStorage !== true ) { self.storageService.setSession(self.cookiesToken, token); } else { self.storageService.set(self.cookiesToken, token); } resolve(self.sessionService.getLogin() ?? ''); }) .catch(() => { reject('sdfsdfsdf'); }); }); } retrieveMe(token: string): Promise { console.log(`AuthService.loginWithToken ... '${token}'`); const self = this; return new Promise((resolve, reject) => { this.http .requestJson({ // server: 'karso', endPoint: 'users/me', requestType: HTTPRequestModel.GET, accept: HTTPMimeType.JSON, contentType: HTTPMimeType.JSON, authorization: `Bearer ${token}`, // special case, the token is set after this request... }) .then((response: ModelResponseHttp) => { // TODO: check type ... console.log(`loginWithToken : get some data to check: ${JSON.stringify(response.data)}`); self.sessionService.create({ //sessionId: response.data.sessionId, userId: response.data.id, userLogin: response.data.login, //userEMail: response.data.email, //userAdmin: response.data.admin, //userBlocked: response.data.blocked, //userRemoved: response.data.removed, //userAvatar: response.data.avatar, tokenJwt: token, }); resolve(true); }) .catch((error: any) => { reject(`return ERROR ${JSON.stringify(error, null, 2)}`); }); }); } create(login: string, email: string, password: string) { return this.createSha(login, email, sha512(password)); } createSha(login: string, email: string, password: string) { let data = { method: 'v?', login: login, email: email, password: password, }; console.log(`call users data=${JSON.stringify(data, null, 2)}`); if (this.identificationVersion === 1) { data.method = 'v1'; } return new Promise((resolve, reject) => { this.http .requestJson({ server: 'karso', endPoint: 'users', requestType: HTTPRequestModel.POST, accept: HTTPMimeType.JSON, contentType: HTTPMimeType.JSON, body: data, }) .then((response: ModelResponseHttp) => { // TODO: check type ... console.log(`createSha : get some data to check: ${JSON.stringify(response.data)}`); resolve(response.data); }) .catch((error: any) => { reject(`return ERROR ${JSON.stringify(error, null, 2)}`); }); }); } isAuthenticated(): boolean { // return !!Session.userId; return false; } isAuthorized(authorizedRoles: string): boolean { /* if (!angular.isArray(_authorizedRoles)) { authorizedRoles = [_authorizedRoles]; } return ( authService.isAuthenticated() && _authorizedRoles.indexOf(Session.userRole) !== -1 ); */ return false; } }