Skip to content

Commit c920a0f

Browse files
committed
chore(api): refactoring
Fixes #49
1 parent cdaf04b commit c920a0f

31 files changed

+514
-306
lines changed

modules/services/api/src/auth/auth.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Module } from '@nestjs/common';
22
import { JwtModule } from '@nestjs/jwt';
33
import { TypeOrmModule } from '@nestjs/typeorm';
4+
import { RedisService } from '@vidya/api/shared/services';
45
import { Role, User, UserRole } from '@vidya/entities';
56

67
import { OtpController } from './controllers/otp.controller';
@@ -24,6 +25,7 @@ import { RevokedTokensService } from './services/revokedTokens.service';
2425
AuthService,
2526
RevokedTokensService,
2627
AuthRolesMappingProfile,
28+
RedisService,
2729
],
2830
})
2931
export class AuthModule {}

modules/services/api/src/auth/controllers/user-authentication.controller.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,19 @@ import {
1616
ApiTooManyRequestsResponse,
1717
ApiUnauthorizedResponse,
1818
} from '@nestjs/swagger';
19-
import { UserAccessToken } from '@vidya/api/auth/decorators';
2019
import * as dto from '@vidya/api/auth/dto';
21-
import { AuthenticatedUser } from '@vidya/api/auth/guards';
20+
import { AuthenticatedUserGuard } from '@vidya/api/auth/guards';
2221
import {
2322
AuthService,
2423
AuthUsersService,
2524
OtpService,
2625
RevokedTokensService,
2726
} from '@vidya/api/auth/services';
2827
import { AuthConfig } from '@vidya/api/configs';
29-
import { JwtToken, OtpType, Routes } from '@vidya/protocol';
28+
import { OtpType, Routes } from '@vidya/protocol';
29+
30+
import { Authentication } from '../decorators';
31+
import { UserAuthentication } from '../utils';
3032

3133
@Controller()
3234
@ApiTags('🔐 Authentication')
@@ -102,7 +104,7 @@ export class UserAuthenticationController {
102104
/* -------------------------------------------------------------------------- */
103105

104106
@Post(Routes().auth.signOut())
105-
@UseGuards(AuthenticatedUser)
107+
@UseGuards(AuthenticatedUserGuard)
106108
@ApiBearerAuth()
107109
@ApiOperation({
108110
summary: 'Signs user out',
@@ -125,10 +127,10 @@ export class UserAuthenticationController {
125127
})
126128
async logoutUser(
127129
@Body() request: dto.SignOutRequest,
128-
@UserAccessToken() userAccessToken: JwtToken,
130+
@Authentication() auth: UserAuthentication,
129131
): Promise<dto.SignOutResponse> {
130132
// revoke access token to prevent reusing it
131-
await this.revokedTokensService.revoke(userAccessToken);
133+
await this.revokedTokensService.revoke(auth.accessToken);
132134

133135
// revoke refresh token if still valid
134136
const token = await this.authService.verifyToken(request.refreshToken);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
2+
import { UserAuthentication, VidyaRequest } from '@vidya/api/auth/utils';
3+
4+
export const Authentication = createParamDecorator(
5+
(data, ctx: ExecutionContext) => {
6+
const request = ctx.switchToHttp().getRequest<VidyaRequest>();
7+
const accessToken = request.accessToken;
8+
return new UserAuthentication(accessToken);
9+
},
10+
);
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
export * from './user-id.decorator';
2-
export * from './user-permissions.decorator';
1+
export * from './authentication.decorator';

modules/services/api/src/auth/decorators/user-id.decorator.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

modules/services/api/src/auth/decorators/user-permissions.decorator.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

modules/services/api/src/auth/guards/authenticated-user.guard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { JwtConfig } from '@vidya/api/configs';
1616
import { AccessToken } from '@vidya/protocol';
1717

1818
@Injectable()
19-
export class AuthenticatedUser implements CanActivate {
19+
export class AuthenticatedUserGuard implements CanActivate {
2020
constructor(
2121
@Inject(JwtConfig.KEY)
2222
private readonly jwtConfig: ConfigType<typeof JwtConfig>,

modules/services/api/src/auth/services/auth-users.service.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,17 @@ import { Inject, Injectable, Logger } from '@nestjs/common';
44
import { ConfigType } from '@nestjs/config';
55
import { InjectRepository } from '@nestjs/typeorm';
66
import * as dto from '@vidya/api/auth/dto';
7-
import { AuthConfig, RedisConfig } from '@vidya/api/configs';
7+
import { AuthConfig } from '@vidya/api/configs';
8+
import { RedisService } from '@vidya/api/shared/services';
89
import { Role, User } from '@vidya/entities';
910
import * as entities from '@vidya/entities';
1011
import { UserPermission, UserPermissionsStorageKey } from '@vidya/protocol';
11-
import Redis from 'ioredis';
1212
import { Repository } from 'typeorm';
1313

1414
export type LoginField = 'email' | 'phone';
1515

1616
@Injectable()
1717
export class AuthUsersService {
18-
private readonly redis: Redis;
1918
private readonly logger = new Logger(AuthUsersService.name);
2019

2120
/**
@@ -25,19 +24,13 @@ export class AuthUsersService {
2524
* @param mapper Mapper instance
2625
*/
2726
constructor(
27+
private readonly redis: RedisService,
2828
@InjectRepository(User) private readonly users: Repository<User>,
2929
@InjectRepository(Role) private readonly roles: Repository<Role>,
3030
@InjectMapper() private readonly mapper: Mapper,
31-
@Inject(RedisConfig.KEY)
32-
private readonly redisConfig: ConfigType<typeof RedisConfig>,
3331
@Inject(AuthConfig.KEY)
3432
private readonly authConfig: ConfigType<typeof AuthConfig>,
35-
) {
36-
this.redis = new Redis({
37-
host: redisConfig.host,
38-
port: redisConfig.port,
39-
});
40-
}
33+
) {}
4134

4235
/**
4336
* Finds a user by id.
@@ -113,7 +106,6 @@ export class AuthUsersService {
113106
await this.redis.set(
114107
UserPermissionsStorageKey(userId),
115108
JSON.stringify(permissions),
116-
'EX',
117109
this.authConfig.userPermissionsCacheTtl,
118110
);
119111
}

modules/services/api/src/auth/services/otp.service.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,24 @@
11
import { Inject, Injectable } from '@nestjs/common';
22
import { ConfigType } from '@nestjs/config';
3-
import { OtpConfig, RedisConfig } from '@vidya/api/configs';
3+
import { OtpConfig } from '@vidya/api/configs';
4+
import { RedisService } from '@vidya/api/shared/services';
45
import { Otp, OtpStorageKey, OtpType } from '@vidya/protocol';
5-
import { Redis } from 'ioredis';
66

77
/**
88
* Service for generating and validating one-time passwords (OTPs) using Redis.
99
*/
1010
@Injectable()
1111
export class OtpService {
12-
private readonly client: Redis;
13-
1412
/**
1513
* Constructs an instance of the OTP service.
1614
*
1715
* @param redisConfig - The configuration for connecting to the Redis server.
1816
*/
1917
constructor(
20-
@Inject(RedisConfig.KEY)
21-
private readonly redisConfig: ConfigType<typeof RedisConfig>,
18+
private readonly redis: RedisService,
2219
@Inject(OtpConfig.KEY)
2320
private readonly otpConfig: ConfigType<typeof OtpConfig>,
24-
) {
25-
this.client = new Redis({
26-
host: redisConfig.host,
27-
port: redisConfig.port,
28-
});
29-
}
21+
) {}
3022

3123
/**
3224
* Generates a one-time password for the given login and type.
@@ -40,7 +32,7 @@ export class OtpService {
4032
code: this.generateCode(),
4133
type: type,
4234
};
43-
await this.client.set(OtpStorageKey(login), JSON.stringify(otp), 'EX', 300);
35+
await this.redis.set(OtpStorageKey(login), JSON.stringify(otp), 300);
4436
return otp;
4537
}
4638

@@ -52,7 +44,7 @@ export class OtpService {
5244
*/
5345
async isExpired(login: string): Promise<boolean> {
5446
const key = OtpStorageKey(login);
55-
return !(await this.client.exists(key));
47+
return !(await this.redis.exists(key));
5648
}
5749

5850
/**
@@ -69,13 +61,13 @@ export class OtpService {
6961
*/
7062
async validate(login: string, code: string): Promise<Otp | undefined> {
7163
const key = OtpStorageKey(login);
72-
const stored: Otp = JSON.parse(await this.client.get(key));
64+
const stored: Otp = JSON.parse(await this.redis.get(key));
7365
if (!stored) return undefined;
7466

7567
// if code is correct, expire it immediately
7668
// to prevent replay attacks and multiple logins
7769
if (code === stored.code) {
78-
await this.client.expire(key, 0);
70+
await this.redis.del(key);
7971
return stored;
8072
}
8173

modules/services/api/src/auth/services/revokedTokens.service.ts

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,16 @@
1-
import { Inject, Injectable } from '@nestjs/common';
2-
import { ConfigType } from '@nestjs/config';
3-
import RedisConfig from '@vidya/api/configs/redis.config';
1+
import { Injectable } from '@nestjs/common';
2+
import { RedisService } from '@vidya/api/shared/services';
43
import { RevokedTokenStorageKey } from '@vidya/protocol';
54
import { JwtToken } from '@vidya/protocol';
6-
import { Redis } from 'ioredis';
75

86
@Injectable()
97
export class RevokedTokensService {
10-
private readonly client: Redis;
11-
128
/**
139
* Constructs an instance of the service with the provided Redis configuration.
1410
*
1511
* @param redisConfig The configuration object for Redis
1612
*/
17-
constructor(
18-
@Inject(RedisConfig.KEY)
19-
private readonly redisConfig: ConfigType<typeof RedisConfig>,
20-
) {
21-
this.client = new Redis({
22-
host: redisConfig.host,
23-
port: redisConfig.port,
24-
});
25-
}
13+
constructor(private readonly redis: RedisService) {}
2614

2715
/**
2816
* Checks if the given JWT token has been revoked.
@@ -31,7 +19,7 @@ export class RevokedTokensService {
3119
* @returns A promise that resolves to a boolean indicating whether the token is revoked.
3220
*/
3321
async isRevoked(token: JwtToken): Promise<boolean> {
34-
return (await this.client.exists(RevokedTokenStorageKey(token))) === 1;
22+
return await this.redis.exists(RevokedTokenStorageKey(token));
3523
}
3624

3725
/**
@@ -41,10 +29,9 @@ export class RevokedTokensService {
4129
* @returns A promise that resolves when the token has been successfully revoked.
4230
*/
4331
async revoke(token: JwtToken): Promise<void> {
44-
await this.client.set(
32+
await this.redis.set(
4533
RevokedTokenStorageKey(token),
4634
'revoked',
47-
'EX',
4835
token.exp - token.iat,
4936
);
5037
}

0 commit comments

Comments
 (0)