import { SessionService } from './../services/commons/session.service'; import { HttpInterceptorFn, HttpRequest, HttpHandlerFn, HttpEvent, HttpResponse, HttpErrorResponse, HttpHeaders } from '@angular/common/http'; import { Observable, tap, catchError, throwError, from, switchMap } from 'rxjs'; import { EncryptionService } from '../services/utilities/encryption.service'; import { inject } from '@angular/core'; import { ResponseDto } from '../models/response.dto'; export const AuthInterceptor: HttpInterceptorFn = ( req: HttpRequest, next: HttpHandlerFn ): Observable> => { const encryptionService = inject(EncryptionService); const sessionService = inject(SessionService); /* ----------------------------------------- * 1️⃣ Always attach Authorization header * ----------------------------------------- */ // OCR uses sessionStorage for token now (migrated previously) const token = sessionStorage.getItem('token'); let reqHeaders = req.headers; // Only set application/json if it's not FormData // FormData requests need the browser to set Content-Type with boundary if (!(req.body instanceof FormData)) { reqHeaders = reqHeaders.set('Content-Type', 'application/json'); } if (token) { reqHeaders = reqHeaders.set( 'Authorization', `Bearer ${token}` ); } /* ----------------------------------------- * 2️⃣ Handle encrypted (compressed) requests * ----------------------------------------- */ if ( req.body && typeof req.body === 'object' && req.body.compressed ) { return from(encryptionService.encrypt(req.body.data)).pipe( switchMap(encryptedBody => { const payload = { scopes: req.body.scopes ?? [], data: encryptedBody, target: req.body.target ?? null, compressed: true }; const modifiedReq = req.clone({ body: payload, headers: reqHeaders }); // Use 'any' type for event to avoid strict type mismatch if ResponseDto structure varies return next(modifiedReq).pipe( tap((event: any) => handleResponse(event, sessionService, encryptionService)), catchError((error: HttpErrorResponse) => throwError(() => error) ) ); }) ); } /* ----------------------------------------- * 3️⃣ Non-encrypted requests (GET included) * ----------------------------------------- */ const modifiedReq = req.clone({ headers: reqHeaders }); return next(modifiedReq).pipe( tap((event: any) => handleResponse(event, sessionService, encryptionService)), catchError((error: HttpErrorResponse) => throwError(() => error) ) ); }; function handleResponse( event: HttpEvent, sessionService: SessionService, encryptionService: EncryptionService ): void { if (!(event instanceof HttpResponse) || !event.ok) { return; } // Handle Authenticate Response if (event.url?.endsWith('/authenticate')) { const response = event.body as ResponseDto; if (response?.data?.token) { sessionStorage.setItem('token', response.data.token); } if (response?.data?.companies) { sessionService.setItem('companies', response.data.companies); } } // Handle Authorize Response if (event.url?.endsWith('/authorize')) { const response = event.body as ResponseDto; // Clearing session might be too aggressive if we just logged in, but following source logic // sessionService.clear(); if (response?.data?.token) { sessionStorage.setItem('token', response.data.token); } if (response?.data?.refreshToken) { sessionService.setItem('refreshToken', response.data.refreshToken); } if (response?.data?.userDetails) { sessionService.setItem('userDetails', response.data.userDetails); } if (response?.data?.data) { encryptionService.encrypt(response.data.data) .then(encryptedNav => { sessionService.setItem('nav', encryptedNav); }); } if (response?.data?.companies) { sessionService.setItem( 'companies', response.data.companies ); } } }