import { Injectable } from '@angular/core'; import { TokenResponse } from '@core/typings/token.typing'; import { environment } from '@environment'; @Injectable({ providedIn: 'root' }) export class TokenAdapterService { private isLocalhost = environment.isLocalhost; // time difference (in ms), between the browser clock and the server clock // a negative diff means the server is ahead, a positive means the browser is ahead private diff = 0; // takes the date returned from the API (when the api sent the response) // and determines the difference between the date from the server and the date of the user's computer private async offsetTime ( expirationDate: Date ) { await this.ensureDiffIsSet(); return new Date(expirationDate.getTime() + this.diff).toISOString(); } private async ensureDiffIsSet () { if (!this.diff) { const serverTimeRaw = this.isLocalhost ? '' : await this.getServerTime(); if (serverTimeRaw) { const browserDate = new Date(); const apiDate = new Date(serverTimeRaw); this.diff = browserDate.getTime() - apiDate.getTime(); } } } private getServerTime () { const xmlHttp = this.getXHR(); xmlHttp.open('HEAD', location.href.toString()); xmlHttp.setRequestHeader('Content-Type', 'text/html'); xmlHttp.send(''); return new Promise((res, rej) => { xmlHttp.addEventListener('load', () => { res(xmlHttp.getResponseHeader('Date')); }); xmlHttp.addEventListener('error', () => { res(''); }); }); } private getXHR () { return new XMLHttpRequest(); } async handleTokenRequest ( body: T ): Promise { const expirationDate = new Date(body.expiration); const refreshExpiration = new Date(body.refreshTokenExpiration); body.expiration = await this.offsetTime(expirationDate); body.refreshTokenExpiration = await this.offsetTime(refreshExpiration); return body; } }