882 lines
26 KiB
TypeScript
882 lines
26 KiB
TypeScript
import { Inject, Injectable, InternalServerErrorException } from '@nestjs/common';
|
|
import { OracleDBService } from 'src/db/db.service';
|
|
import { AuthLoginDTO, MailTemplateDTO, MailTypeDTO, SendMailDTO } from './auth.dto';
|
|
import * as oracledb from 'oracledb';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import axios, { AxiosRequestConfig } from 'axios';
|
|
import { Request } from 'express';
|
|
import * as jwkToPem from "jwk-to-pem"
|
|
import * as jwt from "jsonwebtoken"
|
|
import { UnauthorizedException } from 'src/exceptions/unauthorized.exception';
|
|
import { ConflictException } from 'src/exceptions/conflict.exception';
|
|
import { BadRequestException } from 'src/exceptions/badRequest.exception';
|
|
import { MailerService } from '@nestjs-modules/mailer';
|
|
import { JwtService } from '@nestjs/jwt';
|
|
import { UserMaintenanceService } from 'src/oracle/user-maintenance/user-maintenance.service';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
|
|
interface DecodedToken {
|
|
email: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
interface IntrospectResult {
|
|
active: boolean;
|
|
}
|
|
|
|
@Injectable()
|
|
export class AuthService {
|
|
private keyCache: Record<string, string> = {};
|
|
|
|
private readonly KEYCLOAK_URL: string;
|
|
private readonly KEYCLOAK_REALM: string;
|
|
private readonly KEYCLOAK_BASE_URL: string;
|
|
private readonly JWKS_URL: string;
|
|
private readonly TOKENS_INTROSPECT_URL: string;
|
|
private readonly CLIENT_ID: string;
|
|
private readonly CLIENT_SECRET: string;
|
|
private readonly TOKEN_URL: string;
|
|
private readonly USERS_URL: string;
|
|
|
|
|
|
constructor(
|
|
private readonly oracleDBService: OracleDBService,
|
|
private readonly configService: ConfigService,
|
|
private readonly mailService: MailerService,
|
|
private readonly userMaintenanceService: UserMaintenanceService,
|
|
@Inject("REGISTER_SIGN_JWT") readonly REGISTER_SIGN_JWT: JwtService,
|
|
@Inject("REGISTER_VERIFY_JWT") readonly REGISTER_VERIFY_JWT: JwtService
|
|
) {
|
|
|
|
const KEYCLOAK_URL = this.configService.get<string>('KEYCLOAK_URL');
|
|
if (!KEYCLOAK_URL) throw new Error('Environment variable KEYCLOAK_URL is not set');
|
|
this.KEYCLOAK_URL = KEYCLOAK_URL;
|
|
|
|
const KEYCLOAK_REALM = this.configService.get<string>('KEYCLOAK_REALM');
|
|
if (!KEYCLOAK_REALM) throw new Error('Environment variable KEYCLOAK_REALM is not set');
|
|
this.KEYCLOAK_REALM = KEYCLOAK_REALM;
|
|
|
|
const CLIENT_ID = this.configService.get<string>('CLIENT_ID');
|
|
if (!CLIENT_ID) throw new Error('Environment variable KEYCLOAK CLIENT_ID is not set');
|
|
this.CLIENT_ID = CLIENT_ID;
|
|
|
|
const CLIENT_SECRET = this.configService.get<string>('CLIENT_SECRET');
|
|
if (!CLIENT_SECRET) throw new Error('Environment variable KEYCLOAK CLIENT_SECRET is not set');
|
|
this.CLIENT_SECRET = CLIENT_SECRET;
|
|
|
|
this.KEYCLOAK_BASE_URL = `${this.KEYCLOAK_URL}/realms/${this.KEYCLOAK_REALM}/protocol/openid-connect`;
|
|
|
|
this.JWKS_URL = `${this.KEYCLOAK_BASE_URL}/certs`
|
|
|
|
this.TOKENS_INTROSPECT_URL = `${this.KEYCLOAK_BASE_URL}/token/introspect`
|
|
|
|
this.TOKEN_URL = `${this.KEYCLOAK_BASE_URL}/token`
|
|
|
|
this.USERS_URL = `${this.KEYCLOAK_URL}/admin/realms/${this.KEYCLOAK_REALM}/users`;
|
|
|
|
}
|
|
|
|
async login(body: AuthLoginDTO) {
|
|
let connection;
|
|
let rows = [];
|
|
try {
|
|
connection = await this.oracleDBService.getConnection();
|
|
if (!connection) {
|
|
throw new Error('No DB Connected');
|
|
}
|
|
|
|
const result = await connection.execute(
|
|
`BEGIN
|
|
USERLOGIN_PKG.ValidateUser(:P_EMAILADDR,:P_PASSWORD,:p_login_cursor);
|
|
END;`,
|
|
{
|
|
P_EMAILADDR: {
|
|
val: body.P_EMAILADDR,
|
|
type: oracledb.DB_TYPE_NVARCHAR,
|
|
},
|
|
P_PASSWORD: {
|
|
val: body.P_PASSWORD,
|
|
type: oracledb.DB_TYPE_NVARCHAR,
|
|
},
|
|
p_login_cursor: {
|
|
type: oracledb.CURSOR,
|
|
dir: oracledb.BIND_OUT,
|
|
},
|
|
},
|
|
{
|
|
outFormat: oracledb.OUT_FORMAT_OBJECT,
|
|
},
|
|
);
|
|
|
|
if (result.outBinds && result.outBinds.p_login_cursor) {
|
|
const cursor = result.outBinds.p_login_cursor;
|
|
let rowsBatch;
|
|
|
|
do {
|
|
rowsBatch = await cursor.getRows(100);
|
|
rows = rows.concat(rowsBatch);
|
|
} while (rowsBatch.length > 0);
|
|
|
|
await cursor.close();
|
|
} else {
|
|
throw new BadRequestException('Error executing request try after some time!');
|
|
}
|
|
|
|
if (rows[0]['ERRORMESG']) {
|
|
throw new BadRequestException('Invalid username or password!');
|
|
}
|
|
return { msg: 'Logged in successfully' };
|
|
} catch (err) {
|
|
throw new BadRequestException('Invalid username or password');
|
|
}
|
|
finally {
|
|
if (connection) {
|
|
try {
|
|
await connection.close();
|
|
} catch (closeErr) {
|
|
console.error('Failed to close connection:', closeErr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private async getPublicKey(kid: string): Promise<string> {
|
|
try {
|
|
// Check if the key is already cached
|
|
if (this.keyCache[kid]) return this.keyCache[kid];
|
|
|
|
// Fetch the JWKS (JSON Web Key Set)
|
|
const { data } = await axios.get(this.JWKS_URL);
|
|
|
|
// Validate the response shape
|
|
if (!data?.keys || !Array.isArray(data.keys)) {
|
|
console.log("Invalid JWKS response");
|
|
throw new UnauthorizedException('Authentication failed');
|
|
}
|
|
|
|
// Find the key with the matching kid
|
|
const key = data.keys.find((k) => k.kid === kid);
|
|
if (!key) {
|
|
console.log("Authentication failed: Key not found");
|
|
throw new UnauthorizedException('Authentication failed');
|
|
}
|
|
|
|
// Convert JWK to PEM format and cache it
|
|
const pem = jwkToPem(key);
|
|
this.keyCache[kid] = pem;
|
|
|
|
return pem;
|
|
} catch (error) {
|
|
if (error instanceof UnauthorizedException) {
|
|
throw error; // Let UnauthorizedException bubble up as-is
|
|
}
|
|
// Optionally log error details for debugging
|
|
console.error('Failed to retrieve or process JWKS:', error);
|
|
// Wrap other errors as InternalServerException
|
|
console.log('Failed to retrieve public key');
|
|
throw new InternalServerErrorException();
|
|
}
|
|
}
|
|
|
|
async introspectToken(token: string): Promise<IntrospectResult> {
|
|
try {
|
|
const decoded = jwt.decode(token) as DecodedToken;
|
|
|
|
const { email } = decoded;
|
|
|
|
if (!email) throw new UnauthorizedException('Authentication failed');
|
|
|
|
const sessionData = await this.getUserSession(email);
|
|
|
|
return { active: Array.isArray(sessionData) && sessionData.length > 0 };
|
|
|
|
} catch (error: any) {
|
|
console.log("Error in introspectToken:", error.message || error);
|
|
|
|
if (error instanceof UnauthorizedException) {
|
|
throw error;
|
|
}
|
|
|
|
throw new InternalServerErrorException('Failed to introspect token');
|
|
}
|
|
}
|
|
|
|
async getUserSession(email: string) {
|
|
try {
|
|
const uid = await this.getUserIdByEmail(email);
|
|
|
|
if (!uid) throw new UnauthorizedException('No user ID found for email.');
|
|
|
|
const userInfoUrl = `${this.USERS_URL}/${uid}/sessions`;
|
|
|
|
const adminToken = await this.getAdminAccessToken();
|
|
|
|
const response = await axios.get(userInfoUrl, {
|
|
headers: {
|
|
Authorization: `Bearer ${adminToken}`,
|
|
},
|
|
});
|
|
|
|
const sessionData = response.data;
|
|
|
|
return sessionData
|
|
|
|
} catch (error) {
|
|
if (error instanceof UnauthorizedException) throw error
|
|
console.log("Error while getting User session.....");
|
|
throw new InternalServerErrorException()
|
|
}
|
|
}
|
|
|
|
async decodeToken(token: string): Promise<any> {
|
|
const decodedHeader = jwt.decode(token, { complete: true });
|
|
|
|
if (!decodedHeader || typeof decodedHeader !== 'object') {
|
|
throw new UnauthorizedException("Authentication failed")
|
|
}
|
|
|
|
const kid: any = decodedHeader.header.kid;
|
|
|
|
const publicKey = await this.getPublicKey(kid);
|
|
|
|
const introspection = await this.introspectToken(token);
|
|
|
|
if (!introspection.active) {
|
|
console.log("Introspect failed for token");
|
|
throw new UnauthorizedException("Authentication Failed")
|
|
}
|
|
|
|
const verified = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
|
|
|
|
return verified;
|
|
}
|
|
|
|
async loginUser(username: string, password: string, req: Request): Promise<any> {
|
|
|
|
const access_token = req.cookies?.access_token;
|
|
const refresh_token = req.cookies?.refresh_token;
|
|
|
|
const params = new URLSearchParams();
|
|
params.append('grant_type', 'password');
|
|
params.append('client_id', this.CLIENT_ID);
|
|
params.append('client_secret', this.CLIENT_SECRET);
|
|
params.append('username', username);
|
|
params.append('password', password);
|
|
|
|
try {
|
|
const userSession = await this.getUserSession(username)
|
|
|
|
if (access_token && refresh_token && userSession.length > 0) {
|
|
let tokens = await this.getTokenFromRefreshToken(req);
|
|
const decoded = jwt.decode(access_token, { complete: true });
|
|
const email: any = (decoded && typeof decoded === 'object') ? (decoded as any).payload?.email : undefined;
|
|
return { ...tokens, email }
|
|
}
|
|
|
|
const response = await axios.post(this.TOKEN_URL, params, {
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
});
|
|
|
|
let k = { ...response.data, email: username };
|
|
|
|
return k;
|
|
} catch (error) {
|
|
console.log("error while logging : ", error.message);
|
|
|
|
throw new BadRequestException('Invalid username or password');
|
|
}
|
|
}
|
|
|
|
async getUserIdByEmail(email: string): Promise<string> {
|
|
try {
|
|
const adminAccessToken = await this.getAdminAccessToken();
|
|
const url = `${this.USERS_URL}?email=${encodeURIComponent(email)}`;
|
|
const options: AxiosRequestConfig = {
|
|
method: 'GET',
|
|
url,
|
|
headers: {
|
|
Authorization: `Bearer ${adminAccessToken}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
};
|
|
|
|
const response = await axios.request(options);
|
|
|
|
if (response.status !== 200 || !Array.isArray(response.data)) {
|
|
console.log("failed to retrieve user-id....");
|
|
throw new UnauthorizedException("Authentication failed")
|
|
}
|
|
|
|
const user = response.data[0];
|
|
if (user?.id) {
|
|
return user.id
|
|
} else {
|
|
throw new UnauthorizedException("Authentication failed")
|
|
}
|
|
|
|
} catch (error) {
|
|
console.log("Error in getUserIdByEmail ...........");
|
|
if (error instanceof UnauthorizedException) {
|
|
throw error
|
|
}
|
|
|
|
throw new InternalServerErrorException();
|
|
}
|
|
}
|
|
|
|
async getUserDetailsByEmail(email: string): Promise<any> {
|
|
try {
|
|
const adminAccessToken = await this.getAdminAccessToken();
|
|
|
|
const userResponse = await axios.get(`${this.USERS_URL}?email=${encodeURIComponent(email)}`, {
|
|
headers: {
|
|
Authorization: `Bearer ${adminAccessToken}`
|
|
},
|
|
});
|
|
|
|
if (userResponse.status !== 200 || !Array.isArray(userResponse.data)) {
|
|
console.log("userResponse : ", userResponse);
|
|
console.log("userResponse status : ", userResponse.status);
|
|
|
|
throw new UnauthorizedException("Authentication failed");
|
|
}
|
|
|
|
const user = userResponse.data[0];
|
|
|
|
if (userResponse.data.length === 0 || !user?.id) {
|
|
throw new BadRequestException("Invalid User");
|
|
}
|
|
const roleUrl = `${this.USERS_URL}/${user.id}/role-mappings`;
|
|
|
|
const roleResponse = await axios.get(roleUrl, {
|
|
headers: {
|
|
Authorization: `Bearer ${adminAccessToken}`
|
|
},
|
|
});
|
|
|
|
const clientRoles = roleResponse.data;
|
|
|
|
return {
|
|
id: user.id,
|
|
email: user.email,
|
|
forgotPassword: user.attributes?.["forgot-password"][0] || null,
|
|
role: clientRoles.clientMappings?.[this.CLIENT_ID]?.mappings?.map((x) => x.name) || []
|
|
};
|
|
|
|
} catch (error) {
|
|
console.log(error.message);
|
|
|
|
console.log("Error in getUserDetailsByEmail ...........");
|
|
if (error instanceof UnauthorizedException) {
|
|
throw error;
|
|
}
|
|
else if (error instanceof BadRequestException) {
|
|
throw error;
|
|
}
|
|
throw new InternalServerErrorException();
|
|
}
|
|
}
|
|
|
|
|
|
async forgotPassword(body: AuthLoginDTO, req: Request) {
|
|
|
|
let det = await req['user'];
|
|
if (det?.email !== body.P_EMAILADDR) {
|
|
throw new BadRequestException();
|
|
}
|
|
|
|
const userDetails = await this.getUserDetailsByEmail(body.P_EMAILADDR);
|
|
|
|
if (userDetails.forgotPassword !== det.rstID) {
|
|
throw new UnauthorizedException("Token verification failed");
|
|
}
|
|
|
|
let adminAccessToken = await this.getAdminAccessToken();
|
|
|
|
console.log(`${this.USERS_URL}/${userDetails.id}/reset-password`);
|
|
|
|
|
|
const options2: AxiosRequestConfig = {
|
|
method: 'PUT',
|
|
url: `${this.USERS_URL}/${userDetails.id}/reset-password`,
|
|
headers: {
|
|
Authorization: `Bearer ${adminAccessToken}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
data: {
|
|
type: 'password',
|
|
value: body.P_PASSWORD,
|
|
temporary: false,
|
|
}
|
|
};
|
|
|
|
try {
|
|
const { data } = await axios.request(options2);
|
|
|
|
console.log("forgot password status API request", data.status);
|
|
|
|
const forgotPasswordStatus = await this.updateForgotPassword(userDetails)
|
|
|
|
if (!forgotPasswordStatus) {
|
|
throw new InternalServerErrorException("Update forgot-password failed")
|
|
}
|
|
|
|
return { statusCode: 200, message: 'password reset successfull' }
|
|
} catch (error) {
|
|
// console.error(error);
|
|
console.log(error.message);
|
|
|
|
throw new InternalServerErrorException()
|
|
|
|
}
|
|
}
|
|
|
|
async getAdminAccessToken() {
|
|
try {
|
|
const adminParams = new URLSearchParams({
|
|
grant_type: 'client_credentials',
|
|
client_id: this.CLIENT_ID,
|
|
client_secret: this.CLIENT_SECRET,
|
|
});
|
|
|
|
const { data } = await axios.post(this.TOKEN_URL, adminParams, {
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
timeout: 6000, // optional: add a timeout to avoid hanging requests
|
|
});
|
|
|
|
if (!data.access_token) {
|
|
console.log("failed to retrieve admin access token.....");
|
|
throw new UnauthorizedException("Authentication failed")
|
|
}
|
|
|
|
return data.access_token;
|
|
|
|
} catch (error) {
|
|
if (error instanceof UnauthorizedException) throw error
|
|
console.log("Error in getAdminAccessToken");
|
|
throw new InternalServerErrorException();
|
|
}
|
|
}
|
|
|
|
async registerUser(body: AuthLoginDTO, req: Request) {
|
|
let det = await req['user'];
|
|
if (det?.email !== body.P_EMAILADDR) {
|
|
throw new BadRequestException();
|
|
}
|
|
const userPayload = {
|
|
username: body.P_EMAILADDR,
|
|
// firstName:"A",
|
|
// lastName:"B",
|
|
email: body.P_EMAILADDR,
|
|
emailVerified: true,
|
|
enabled: true,
|
|
attributes: {
|
|
"forgot-password": ["none"]
|
|
},
|
|
credentials: [
|
|
{
|
|
type: 'password',
|
|
value: body.P_PASSWORD,
|
|
temporary: false,
|
|
},
|
|
],
|
|
};
|
|
|
|
console.log(userPayload);
|
|
|
|
const adminAccessToken = await this.getAdminAccessToken();
|
|
|
|
try {
|
|
const response = await axios.post(this.USERS_URL, userPayload, {
|
|
headers: {
|
|
Authorization: `Bearer ${adminAccessToken}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (response.status === 201) {
|
|
|
|
const uid = await this.getUserIdByEmail(body.P_EMAILADDR);
|
|
|
|
let ROLE = "";
|
|
|
|
const response: any = await this.userMaintenanceService.ValidateEmail({ P_EMAILADDR: body.P_EMAILADDR })
|
|
|
|
|
|
if (Array.isArray(response) && !response[0].ERRORMESG) {
|
|
switch (response[0].SOURCE) {
|
|
case "USCIB": ROLE = 'ua'; break;
|
|
case "SP": ROLE = 'sa'; break;
|
|
case "CLIENT": ROLE = 'ca'; break;
|
|
}
|
|
}
|
|
else if (Array.isArray(response) && response[0].ERRORMESG) {
|
|
throw new BadRequestException();
|
|
}
|
|
|
|
if (!ROLE) {
|
|
console.log("ERROR while giving access : ");
|
|
throw new InternalServerErrorException();
|
|
}
|
|
|
|
const res = await this.assignRoleToUser(uid, ROLE);
|
|
|
|
console.log(res);
|
|
|
|
return { statusCode: 201, message: 'User registered successfully' };
|
|
}
|
|
|
|
} catch (error) {
|
|
console.log(error.message);
|
|
|
|
if (error.message === "Request failed with status code 409") {
|
|
throw new ConflictException("User already exist");
|
|
}
|
|
else if (error instanceof BadRequestException) {
|
|
console.log("ERROR while registering : ", error.message);
|
|
return error;
|
|
}
|
|
console.log("ERROR while giving access : ", error.message);
|
|
throw new InternalServerErrorException('Failed to create user');
|
|
}
|
|
}
|
|
|
|
async logoutUser(refreshToken: string): Promise<any> {
|
|
const url = `${this.KEYCLOAK_BASE_URL}/logout`;
|
|
|
|
const params = new URLSearchParams();
|
|
params.append('client_id', this.CLIENT_ID);
|
|
params.append('client_secret', this.CLIENT_SECRET);
|
|
params.append('refresh_token', refreshToken);
|
|
|
|
try {
|
|
const response = await axios.post(url, params, {
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
});
|
|
return { statusCode: 200, message: 'Logged-Out successfully' };
|
|
} catch (error) {
|
|
throw new InternalServerErrorException('Logout failed');
|
|
}
|
|
}
|
|
|
|
async getClientUUID(): Promise<string> {
|
|
try {
|
|
const token = await this.getAdminAccessToken();
|
|
|
|
const realm = this.KEYCLOAK_REALM;
|
|
const clientId = this.CLIENT_ID;
|
|
const keycloakUrl = this.KEYCLOAK_URL;
|
|
|
|
const response = await axios.get(
|
|
`${keycloakUrl}/admin/realms/${realm}/clients?clientId=${encodeURIComponent(clientId)}`,
|
|
{
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
validateStatus: () => true, // manually handle status codes
|
|
}
|
|
);
|
|
|
|
if (response.status !== 200) {
|
|
throw new Error(`Failed to fetch client list. Status: ${response.status}. Message: ${JSON.stringify(response.data)}`);
|
|
}
|
|
|
|
const clients = response.data;
|
|
|
|
if (!Array.isArray(clients) || clients.length === 0) {
|
|
throw new Error(`Client with ID '${clientId}' not found in realm '${realm}'.`);
|
|
}
|
|
|
|
const clientUUID = clients[0].id;
|
|
|
|
if (!clientUUID) {
|
|
throw new Error(`Client UUID is missing in the response for clientId '${clientId}'.`);
|
|
}
|
|
|
|
return clientUUID;
|
|
} catch (error) {
|
|
console.error('❌ Error in getClientUUID:', error.message || error);
|
|
throw error; // rethrow for upstream handling
|
|
}
|
|
}
|
|
|
|
async getClientRole(roleName: string): Promise<any> {
|
|
const token = await this.getAdminAccessToken();
|
|
|
|
const clientUUID = await this.getClientUUID();
|
|
|
|
try {
|
|
const response = await axios.get(
|
|
`${this.KEYCLOAK_URL}/admin/realms/${this.KEYCLOAK_REALM}/clients/${clientUUID}/roles/${roleName}`,
|
|
{
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
},
|
|
);
|
|
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error(`Error getting client role '${roleName}'`);
|
|
console.error(error.response?.data || error.message);
|
|
throw new InternalServerErrorException(`Could not find client role '${roleName}'`);
|
|
}
|
|
}
|
|
|
|
async assignRoleToUser(userId: string, roleName: string): Promise<any> {
|
|
try {
|
|
const token = await this.getAdminAccessToken();
|
|
|
|
const clientId = await this.getClientUUID();
|
|
|
|
const role = await this.getClientRole(roleName);
|
|
|
|
const url = `${this.KEYCLOAK_URL}/admin/realms/${this.KEYCLOAK_REALM}/users/${userId}/role-mappings/clients/${clientId}`;
|
|
|
|
const response = await axios.post(
|
|
url,
|
|
[role],
|
|
{
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
validateStatus: () => true, // To manually check status if needed
|
|
}
|
|
);
|
|
|
|
if (response.status >= 200 && response.status < 300) {
|
|
console.log(`✅ Role "${roleName}" successfully assigned to user ${userId}.`);
|
|
|
|
return { message: "Successfully assigned to user" }
|
|
} else {
|
|
throw new Error(`❌ Failed to assign role. Status: ${response.status}. Data: ${JSON.stringify(response.data)}`);
|
|
}
|
|
} catch (error) {
|
|
console.error(`🔥 Error assigning role "${roleName}" to user ${userId}:`, error.message || error);
|
|
throw error; // Rethrow to allow upstream handling
|
|
}
|
|
}
|
|
|
|
async getTokenFromRefreshToken(req: Request) {
|
|
|
|
const refreshToken = req.cookies['refresh_token'];
|
|
|
|
if (!refreshToken) {
|
|
|
|
console.log("refesh token not present");
|
|
|
|
throw new UnauthorizedException('Authentication failed');
|
|
|
|
}
|
|
|
|
const params = new URLSearchParams();
|
|
params.append('grant_type', 'refresh_token');
|
|
params.append('client_id', this.CLIENT_ID);
|
|
params.append('client_secret', this.CLIENT_SECRET);
|
|
params.append('refresh_token', refreshToken);
|
|
|
|
// console.log("url for refresh is : ", `${this.KEYCLOAK_URL}/auth/realms/${this.KEYCLOAK_REALM}/protocol/openid-connect/token`);
|
|
|
|
try {
|
|
const response = await axios.post(this.TOKEN_URL, params, {
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
});
|
|
|
|
return response.data;
|
|
} catch (error) {
|
|
if (axios.isAxiosError(error) && error.response) {
|
|
console.error('🔴 Axios error:', {
|
|
status: error.response.status,
|
|
data: error.response.data,
|
|
});
|
|
} else {
|
|
console.error('🔴 Unexpected error:', error.message);
|
|
}
|
|
console.log("Error while refreshing tokens : ", error.message);
|
|
throw new UnauthorizedException('Authentication failed');
|
|
}
|
|
}
|
|
|
|
async getMailTemplate(body: SendMailDTO, token: string, source: string): Promise<MailTemplateDTO | null> {
|
|
|
|
switch (body.P_MAIL_TYPE) {
|
|
case MailTypeDTO.REGISTER_CLIENT:
|
|
return {
|
|
to: body.P_TO,
|
|
subject: `🔐 Register Your Account`,
|
|
template: 'a',
|
|
context: {
|
|
to: body.P_TO,
|
|
url: `https://client.alphaomegainfosys.com/register/${token}`
|
|
}
|
|
}
|
|
case MailTypeDTO.FORGOT_PASSWORD:
|
|
return {
|
|
to: body.P_TO,
|
|
subject: `Reset your password`,
|
|
template: 'b',
|
|
context: {
|
|
to: body.P_TO,
|
|
url: `${source === 'ua' ? `https://policy.alphaomegainfosys.com/register/${token}`
|
|
: source === 'sa' ? `https://sp.alphaomegainfosys.com/register/${token}`
|
|
: source === 'ca' ? `https://client.alphaomegainfosys.com/register/${token}` : ''}`
|
|
}
|
|
}
|
|
|
|
// case MailTypeDTO.DEMO_MAIL:
|
|
// return {
|
|
// to: body.P_TO,
|
|
// subject: `Testing`,
|
|
// template: 'demo',
|
|
// context: {
|
|
// to: body.P_TO,
|
|
// url: `https://client.alphaomegainfosys.com/register/${token}`
|
|
// }
|
|
// }
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async generateUUID() {
|
|
try {
|
|
const uuid = uuidv4();
|
|
|
|
if (!uuid || typeof uuid !== 'string') {
|
|
throw new InternalServerErrorException('Invalid UUID generated');
|
|
}
|
|
|
|
return uuid;
|
|
} catch (error) {
|
|
console.error('UUID generation failed:', error.message);
|
|
throw new InternalServerErrorException('Failed to generate unique ID');
|
|
}
|
|
}
|
|
|
|
async generateToken(payload: { P_TO: string, uuid?: string }) {
|
|
let token: string;
|
|
try {
|
|
if (payload.uuid) {
|
|
token = this.REGISTER_SIGN_JWT.sign({ email: payload.P_TO, rstID: payload.uuid });
|
|
}
|
|
else {
|
|
token = this.REGISTER_SIGN_JWT.sign({ email: payload.P_TO });
|
|
}
|
|
console.log("Register token : ", token);
|
|
|
|
if (!token) {
|
|
console.log("Register Token Generation failed");
|
|
throw new InternalServerErrorException();
|
|
}
|
|
|
|
return token;
|
|
}
|
|
catch (error) {
|
|
console.log(error.message);
|
|
|
|
throw new InternalServerErrorException("Register Token Generation failed")
|
|
}
|
|
}
|
|
|
|
async updateForgotPassword(user: any, rstID?: string) {
|
|
try {
|
|
const adminAccessToken = await this.getAdminAccessToken();
|
|
|
|
const options2: AxiosRequestConfig = {
|
|
method: 'PUT',
|
|
url: `${this.USERS_URL}/${user.id}`,
|
|
headers: {
|
|
Authorization: `Bearer ${adminAccessToken}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
data: {
|
|
"username": `${user.email}`,
|
|
// firstName:"A",
|
|
// lastName:"B",
|
|
"email": `${user.email}`,
|
|
"emailVerified": true,
|
|
"enabled": true,
|
|
"attributes": {
|
|
"forgot-password": [`${rstID ? rstID : "none"}`]
|
|
}
|
|
}
|
|
};
|
|
|
|
const userResponse = await axios.request(options2);
|
|
|
|
if (userResponse.status !== 204) {
|
|
console.log("Error updating forgot-password : ");
|
|
throw new InternalServerErrorException();
|
|
}
|
|
|
|
return true;
|
|
|
|
} catch (error) {
|
|
|
|
console.log("Error updating forgot password");
|
|
console.log("Error : ", error.message);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async sendMail(body: SendMailDTO) {
|
|
console.log("mail body : ", body);
|
|
let token: string;
|
|
let ROLE: string = "";
|
|
let uuid: string | undefined = undefined;
|
|
let userDetails: any | null = null;
|
|
|
|
if (body.P_MAIL_TYPE === MailTypeDTO.FORGOT_PASSWORD) {
|
|
try {
|
|
uuid = await this.generateUUID();
|
|
|
|
userDetails = await this.getUserDetailsByEmail(body.P_TO);
|
|
|
|
ROLE = userDetails.role[0];
|
|
|
|
} catch (error) {
|
|
if (error instanceof BadRequestException) {
|
|
throw error
|
|
}
|
|
|
|
throw new InternalServerErrorException();
|
|
}
|
|
}
|
|
|
|
token = await this.generateToken({ P_TO: body.P_TO, uuid: uuid })
|
|
|
|
|
|
|
|
const mailTemplate: MailTemplateDTO | null = await this.getMailTemplate(body, token, ROLE);
|
|
|
|
if (!mailTemplate) {
|
|
throw new BadRequestException();
|
|
}
|
|
|
|
try {
|
|
await this.mailService.sendMail({ ...mailTemplate });
|
|
console.log('Email sent successfully');
|
|
|
|
if (body.P_MAIL_TYPE === MailTypeDTO.FORGOT_PASSWORD) {
|
|
let forgotPasswordStatus = await this.updateForgotPassword(userDetails, uuid);
|
|
|
|
if (forgotPasswordStatus) {
|
|
|
|
return { statusCode: 200, message: 'Email sent successfully' };
|
|
}
|
|
|
|
throw new InternalServerErrorException();
|
|
|
|
}
|
|
return { statusCode: 200, message: 'Email sent successfully' };
|
|
|
|
} catch (error) {
|
|
console.error('Failed to send email:', error.message, error);
|
|
throw new InternalServerErrorException();
|
|
}
|
|
}
|
|
|
|
}
|