Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): Add resend otp implementation #445

Merged
merged 10 commits into from
Oct 13, 2024
4 changes: 0 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,3 @@ FEEDBACK_FORWARD_EMAIL=
BACKEND_URL=http://localhost:4200
NEXT_PUBLIC_BACKEND_URL=http://localhost:4200


# Enter time in secs
THROTTLE_TTL=
THROTTLE_LIMIT=
16 changes: 2 additions & 14 deletions apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { FeedbackModule } from '@/feedback/feedback.module'
import { CacheModule } from '@/cache/cache.module'
import { WorkspaceMembershipModule } from '@/workspace-membership/workspace-membership.module'
import { seconds, ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler'

@Module({
controllers: [AppController],
imports: [
Expand All @@ -38,16 +39,7 @@ import { seconds, ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler'
abortEarly: true
}
}),
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => [
{
ttl: seconds(config.get('THROTTLE_TTL')),
limit: config.get('THROTTLE_LIMIT')
}
]
}),

ScheduleModule.forRoot(),
PassportModule,
AuthModule,
Expand Down Expand Up @@ -77,10 +69,6 @@ import { seconds, ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler'
{
provide: APP_GUARD,
useClass: ApiKeyGuard
},
{
provide: APP_GUARD,
useClass: ThrottlerGuard
}
]
})
Expand Down
14 changes: 13 additions & 1 deletion apps/api/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { GoogleOAuthStrategyFactory } from '@/config/factory/google/google-strat
import { GoogleStrategy } from '@/config/oauth-strategy/google/google.strategy'
import { GitlabOAuthStrategyFactory } from '@/config/factory/gitlab/gitlab-strategy.factory'
import { GitlabStrategy } from '@/config/oauth-strategy/gitlab/gitlab.strategy'
import { seconds, ThrottlerModule } from '@nestjs/throttler'
import { ConfigModule, ConfigService } from '@nestjs/config'

@Module({
imports: [
Expand All @@ -21,7 +23,17 @@ import { GitlabStrategy } from '@/config/oauth-strategy/gitlab/gitlab.strategy'
algorithm: 'HS256'
}
}),
UserModule
UserModule,
Prakhargarg-2010196 marked this conversation as resolved.
Show resolved Hide resolved
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => [
{
ttl: seconds(config.get('THROTTLE_TTL')),
Prakhargarg-2010196 marked this conversation as resolved.
Show resolved Hide resolved
limit: config.get('THROTTLE_LIMIT')
}
],
inject: [ConfigService]
})
],
providers: [
AuthService,
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/auth/controller/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import {
sendOAuthSuccessRedirect
} from '@/common/redirect'
import { setCookie } from '@/common/util'
import { seconds, Throttle, ThrottlerGuard } from '@nestjs/throttler'
import { ThrottlerGuard } from '@nestjs/throttler'

@Controller('auth')
export class AuthController {
private readonly logger = new Logger(AuthController.name)
Expand All @@ -49,7 +50,6 @@ export class AuthController {
@Public()
@Post('resend-otp/:email')
@UseGuards(ThrottlerGuard)
@Throttle({ default: { ttl: seconds(1), limit: 2 } })
async resendOtp(
@Param('email')
email: string
Expand Down
28 changes: 7 additions & 21 deletions apps/api/src/auth/service/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,10 @@ export class AuthService {
this.logger.error(`Invalid email address: ${email}`)
throw new BadRequestException('Please enter a valid email address')
}
try {
const user = await this.createUserIfNotExists(
email,
AuthProvider.EMAIL_OTP
)
const otp = await generateOtp(email, user.id, this.prisma)
await this.mailService.sendOtp(email, otp.code)
} catch (e) {
throw e
}

const user = await this.createUserIfNotExists(email, AuthProvider.EMAIL_OTP)
const otp = await generateOtp(email, user.id, this.prisma)
await this.mailService.sendOtp(email, otp.code)

this.logger.log(`Login code sent to ${email}`)
}
Expand All @@ -61,17 +55,9 @@ export class AuthService {
* @param email The email address to resend the login code to
*/
async resendOtp(email: string): Promise<void> {
/**
*TODO Resend the otp based on another function send otp but
*TODO with a throttler to rate limit the api
*/
try {
const user = await getUserByEmailOrId(email, this.prisma)
const otp = await generateOtp(email, user.id, this.prisma)
await this.mailService.sendOtp(email, otp.code)
} catch (e) {
this.logger.error(`Resending OTP failed ${e}`)
}
const user = await getUserByEmailOrId(email, this.prisma)
const otp = await generateOtp(email, user.id, this.prisma)
await this.mailService.sendOtp(email, otp.code)
}

/* istanbul ignore next */
Expand Down
4 changes: 3 additions & 1 deletion apps/api/src/common/env/env.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ const generalSchema = z.object({
MINIO_BUCKET_NAME: z.string().optional(),
MINIO_USE_SSL: z.string().optional(),

FEEDBACK_FORWARD_EMAIL: z.string().email()
FEEDBACK_FORWARD_EMAIL: z.string().email(),
THROTTLE_TTL: z.string().transform((val) => parseInt(val, 10)), // Convert string to number
THROTTLE_LIMIT: z.string().transform((val) => parseInt(val, 10)) // Convert string to number
})

export type EnvSchemaType = z.infer<typeof generalSchema>
Expand Down
52 changes: 28 additions & 24 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.