Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions apps/api-gateway/src/authz/authz.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ import { User } from './decorators/user.decorator';
import { user } from '@prisma/client';
import * as useragent from 'express-useragent';
import { EmptyStringParamPipe, TrimStringParamPipe } from '@credebl/common/cast.helper';
import { Roles } from './decorators/roles.decorator';
import { OrgRoles } from 'libs/org-roles/enums';
import { OrgRolesGuard } from './guards/org-roles.guard';

@Controller('auth')
@ApiTags('auth')
Expand Down Expand Up @@ -143,6 +146,34 @@ export class AuthzController {
return res.status(HttpStatus.CREATED).json(finalResponse);
}

@Post('/verify-mail-manually')
@ApiResponse({ status: HttpStatus.CREATED, description: 'Created', type: ApiResponseDto })
@UseGuards(AuthGuard('jwt'), OrgRolesGuard)
@Roles(OrgRoles.PLATFORM_ADMIN)
@ApiBearerAuth()
@ApiQuery({
name: 'clientAlias',
required: false,
enum: (process.env.SUPPORTED_SSO_CLIENTS || '')
.split(',')
.map((alias) => alias.trim()?.toUpperCase())
.filter(Boolean)
})
@ApiOperation({ summary: 'Send verification email', description: 'Send verification email to new user' })
async verifyEmailManually(
@Query('clientAlias', ClientAliasValidationPipe) clientAlias: string,
@Body() userEmailVerification: UserEmailVerificationDto,
@Res() res: Response
): Promise<Response> {
userEmailVerification.clientAlias = clientAlias ?? (await getDefaultClient()).alias;
await this.authzService.sendVerificationMail(userEmailVerification);
const finalResponse: IResponseType = {
statusCode: HttpStatus.CREATED,
message: ResponseMessages.user.success.verificationSuccess
};
return res.status(HttpStatus.CREATED).json(finalResponse);
}

/**
* Registers a new user on the platform.
*
Expand Down
1 change: 1 addition & 0 deletions apps/api-gateway/src/authz/authz.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export class AuthzService extends BaseService {
}

async sendVerificationMail(userEmailVerification: UserEmailVerificationDto): Promise<user> {
userEmailVerification.isDefaultVerified = true;
const payload = { userEmailVerification };
return this.natsClient.sendNatsMessage(this.authServiceProxy, 'send-verification-mail', payload);
Comment on lines +45 to 47
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Don’t auto-set isDefaultVerified for every send path.

sendVerificationMail now flips the flag to true for every caller, which makes the downstream user service treat every user as already verified and skip the email entirely—exactly the abuse scenario we’re trying to avoid. Please keep the default false (from the DTO) and only set it to true in the specific flows that really need auto-verification (e.g., a manual approval path) rather than here.

Apply this diff so the caller decides the flag:

-    userEmailVerification.isDefaultVerified = true;
+    if (userEmailVerification.isDefaultVerified === undefined) {
+      userEmailVerification.isDefaultVerified = false;
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
userEmailVerification.isDefaultVerified = true;
const payload = { userEmailVerification };
return this.natsClient.sendNatsMessage(this.authServiceProxy, 'send-verification-mail', payload);
if (userEmailVerification.isDefaultVerified === undefined) {
userEmailVerification.isDefaultVerified = false;
}
const payload = { userEmailVerification };
return this.natsClient.sendNatsMessage(this.authServiceProxy, 'send-verification-mail', payload);
🤖 Prompt for AI Agents
In apps/api-gateway/src/authz/authz.service.ts around lines 45 to 47, the code
currently forces userEmailVerification.isDefaultVerified = true before sending
the message which causes downstream services to skip real verification; remove
that assignment so the DTO's default (false) is preserved and send the payload
as-is, and update any specific flows that legitimately require auto-verification
to set isDefaultVerified = true before calling this method instead of here.

}
Expand Down
9 changes: 7 additions & 2 deletions apps/api-gateway/src/user/dto/create-user.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, IsOptional, IsString, IsUrl, MaxLength } from 'class-validator';
import { ApiHideProperty, ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsString, IsUrl, MaxLength } from 'class-validator';
import { toLowerCase, trim } from '@credebl/common/cast.helper';

import { Transform } from 'class-transformer';
Expand Down Expand Up @@ -38,4 +38,9 @@ export class UserEmailVerificationDto {
@IsString({ message: 'clientAlias should be string' })
@Transform(({ value }) => trim(value))
clientAlias?: string;

@ApiHideProperty()
@IsOptional()
@IsBoolean({ message: 'isDefaultVerified should be boolean' })
isDefaultVerified: boolean = false;
}
31 changes: 18 additions & 13 deletions apps/user/src/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class UserService {

async sendVerificationMail(userEmailVerification: ISendVerificationEmail): Promise<user> {
try {
const { email, brandLogoUrl, platformName, clientAlias } = userEmailVerification;
const { email, brandLogoUrl, platformName, clientAlias, isDefaultVerified } = userEmailVerification;

if ('PROD' === process.env.PLATFORM_PROFILE_MODE) {
// eslint-disable-next-line prefer-destructuring
Expand Down Expand Up @@ -150,27 +150,32 @@ export class UserService {
if (!redirectUrl) {
throw new NotFoundException(ResponseMessages.user.error.redirectUrlNotFound);
}

sendVerificationMail = await this.sendEmailForVerification({
email,
verificationCode: verifyCode,
redirectUrl,
clientId: clientDetails.clientId,
brandLogoUrl,
platformName,
redirectTo: clientDetails.domain,
clientAlias
});
if (!isDefaultVerified) {
sendVerificationMail = await this.sendEmailForVerification({
email,
verificationCode: verifyCode,
redirectUrl,
clientId: clientDetails.clientId,
brandLogoUrl,
platformName,
redirectTo: clientDetails.domain,
clientAlias
});
}
} catch (error) {
throw new InternalServerErrorException(ResponseMessages.user.error.emailSend);
}

if (sendVerificationMail) {
if (sendVerificationMail || isDefaultVerified) {
const uniqueUsername = await this.createUsername(email, verifyCode);
userEmailVerification.username = uniqueUsername;
userEmailVerification.clientId = clientDetails.clientId;
userEmailVerification.clientSecret = clientDetails.clientSecret;
const resUser = await this.userRepository.createUser(userEmailVerification, verifyCode);
if (isDefaultVerified) {
this.logger.debug('In isDefaultVerified block');
await this.verifyEmail({ email, verificationCode: verifyCode });
}
return resUser;
}
} catch (error) {
Expand Down
1 change: 1 addition & 0 deletions libs/common/src/interfaces/user.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface ISendVerificationEmail {
platformName?: string;
redirectTo?: string;
clientAlias?: string;
isDefaultVerified?: boolean;
}

export interface IClientDetailsSSO {
Expand Down
1 change: 1 addition & 0 deletions libs/common/src/response-messages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const ResponseMessages = {
newUser: 'User not found',
checkEmail: 'User email checked successfully.',
sendVerificationCode: 'Verification link has been successfully sent on the email. Please verify',
verificationSuccess: 'Verification Successful',
userActivity: 'User activities fetched successfully',
platformSettings: 'Platform settings updated',
fetchPlatformSettings: 'Platform settings fetched',
Expand Down