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

Fix login, confirm code #146

Merged
merged 35 commits into from
Dec 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7fb49c2
Fix login, confirm code
PhamAnhHoang Dec 16, 2023
b254591
Refresh token
PhamAnhHoang Dec 16, 2023
7a92875
Refresh token
PhamAnhHoang Dec 16, 2023
7092cd2
Fix unit test
PhamAnhHoang Dec 18, 2023
6e39d89
Add api logout
PhamAnhHoang Dec 18, 2023
4b0f8f3
Add logic that check password reset period
PhamAnhHoang Dec 18, 2023
43b5c6e
Fix reset password
PhamAnhHoang Dec 18, 2023
71f809c
Change api endpoint
PhamAnhHoang Dec 18, 2023
b2c24c6
Fix unit test
PhamAnhHoang Dec 19, 2023
9dcdf45
Fix axios run refresh when access token expired
PhamAnhHoang Dec 20, 2023
85425ad
Fix router
padi-dev-hoangpa Dec 20, 2023
6623436
Fix unit test
PhamAnhHoang Dec 20, 2023
898148b
Lint code
PhamAnhHoang Dec 20, 2023
22f0134
User service unit test
PhamAnhHoang Dec 20, 2023
82991df
Lint file
PhamAnhHoang Dec 20, 2023
d5e81b6
Fix login and add confirm code view
padi-dev-hoangpa Dec 21, 2023
3237383
Lint code
padi-dev-hoangpa Dec 21, 2023
d9db377
Fix navigate to verify code
PhamAnhHoang Dec 21, 2023
4179d4c
Remove console
PhamAnhHoang Dec 21, 2023
6718360
Update logout feature
PhamAnhHoang Dec 21, 2023
aced73b
Fix hook
PhamAnhHoang Dec 21, 2023
5db1cc8
Lint code
PhamAnhHoang Dec 21, 2023
a04f082
Fix request reset password
PhamAnhHoang Dec 21, 2023
301f3d9
Lint code
PhamAnhHoang Dec 21, 2023
fa9c259
Fix login
PhamAnhHoang Dec 22, 2023
5cb2127
Lint code
PhamAnhHoang Dec 22, 2023
967cc37
Fix logout and link to email
PhamAnhHoang Dec 22, 2023
16a57a7
Lint code
PhamAnhHoang Dec 22, 2023
1c6517c
Fix unit test
PhamAnhHoang Dec 22, 2023
36a3a42
Remove yarn lock
PhamAnhHoang Dec 23, 2023
c20fa84
lint
PhamAnhHoang Dec 23, 2023
6a0a0cc
Fix router
PhamAnhHoang Dec 23, 2023
5f772c3
Lint code
PhamAnhHoang Dec 23, 2023
da5f817
Fix build
PhamAnhHoang Dec 23, 2023
1923ae2
Lint code
PhamAnhHoang Dec 23, 2023
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
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ APP_SECRET="such secret wow"
SESSION_SECRET="even more secretIER! :D"

API_URL=http://localhost:3000
PLATFORM_URL=http://localhost:4200

MAIL_HOST=localhost
MAIL_USER=
Expand All @@ -28,3 +29,8 @@ PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
# API
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:4200
PORT=3000

JWT_ACCESS_TOKEN_EXPIRATION_TIME=60
JWT_REFRESH_TOKEN_EXPIRATION_TIME=28800

RESET_PASSWORD_PERIOD=15
4 changes: 0 additions & 4 deletions apps/api/src/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { createMock } from '@golevelup/ts-jest'

import { AuthController } from './auth.controller'
import { AuthService } from './auth.service'
import { ConfirmCodeService } from '../user/confirm-code.service'
import { UserEntity } from '../entities/user.entity'
import { SignUpWithEmailCredentialsDto } from '@isomera/dtos'
import { Pure } from '@isomera/interfaces'
Expand All @@ -26,9 +25,6 @@ describe('Auth Controller', () => {
if (Object.is(token, AuthService)) {
return createMock<AuthService>()
}
if (Object.is(token, ConfirmCodeService)) {
return createMock<ConfirmCodeService>()
}
})
.compile()

Expand Down
46 changes: 36 additions & 10 deletions apps/api/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,20 @@ import { JWTAuthGuard } from './guards/jwt-auth.guard'
import { LocalAuthGuard } from './guards/local-auth.guard'
import { SessionAuthGuard } from './guards/session-auth.guard'
import { TokenInterceptor } from './interceptors/token.interceptor'
import { ConfirmCodeService } from '../user/confirm-code.service'
import {
ConfirmCodeResponseInterface,
LogoutResponseInterface,
PasswordResetPerformInterface,
PasswordResetRequestInterface,
Pure,
RefreshTokenResponseInterface,
StatusType
} from '@isomera/interfaces'
import { JwtRefreshTokenGuard } from './guards/jwt-refresh-token'

@Controller('auth')
export class AuthController {
constructor(
private readonly authService: AuthService,
private readonly confirmCodeService: ConfirmCodeService
) {}
constructor(private readonly authService: AuthService) {}

@Post('register')
@HttpCode(HttpStatus.CREATED)
Expand Down Expand Up @@ -68,12 +68,10 @@ export class AuthController {
@HttpCode(HttpStatus.OK)
async confirmCode(
@Body() body: Pure<ConfirmationCodeDto>
): Promise<UserEntity> {
const user = await this.confirmCodeService.verifyCode(body.code, body.email)

await this.authService.sendGreetings(user)
): Promise<ConfirmCodeResponseInterface> {
const user = await this.authService.verifyCode(body)

return user
return { status: user ? StatusType.OK : StatusType.FAIL }
}

@Get('/me')
Expand All @@ -99,4 +97,32 @@ export class AuthController {
const result = await this.authService.setNewPassword(body)
return { status: result ? StatusType.OK : StatusType.FAIL }
}

@UseGuards(JwtRefreshTokenGuard)
@Post('/refresh')
@HttpCode(HttpStatus.OK)
async refreshToken(
@AuthUser() user: Pure<UserEntity>
): Promise<RefreshTokenResponseInterface> {
const { refresh_token, access_token } = this.authService.signToken(user)

await this.authService.storeRefreshToken(user, refresh_token)
return {
access_token,
refresh_token,
status: StatusType.OK
}
}

@Post('/logout')
@UseGuards(SessionAuthGuard, JWTAuthGuard)
@HttpCode(HttpStatus.OK)
async logout(
@AuthUser() user: Pure<UserEntity>
): Promise<LogoutResponseInterface> {
await this.authService.logout(user)
return {
status: StatusType.OK
}
}
}
13 changes: 11 additions & 2 deletions apps/api/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { JwtStrategy } from './strategies/jwt.strategy'
import { LocalStrategy } from './strategies/local.strategy'
import { MailerModule } from '../mailer/mailer.module'
import { ConfirmCodeModule } from '../user/confirm-code.module'
import { OrganizationModule } from '../organization/organization.module'
import { JwtRefreshTokenStrategy } from './strategies/jwt-refresh-token.strategy'

@Module({
imports: [
Expand All @@ -26,9 +28,16 @@ import { ConfirmCodeModule } from '../user/confirm-code.module'
algorithms: ['HS384']
}
}),
ConfirmCodeModule
ConfirmCodeModule,
OrganizationModule
],
controllers: [AuthController],
providers: [AuthService, LocalStrategy, JwtStrategy, SessionSerializer]
providers: [
AuthService,
LocalStrategy,
JwtStrategy,
SessionSerializer,
JwtRefreshTokenStrategy
]
})
export class AuthModule {}
37 changes: 33 additions & 4 deletions apps/api/src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { ConfirmCodeService } from '../user/confirm-code.service'
import { UserEntity } from '../entities/user.entity'
import { SignUpWithEmailCredentialsDto } from '@isomera/dtos'
import { Pure } from '@isomera/interfaces'
import { OrganizationService } from '../organization/organization.service'
import { ConfigService } from '@nestjs/config'

describe('AuthService', () => {
let service: AuthService
Expand All @@ -20,7 +22,24 @@ describe('AuthService', () => {

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AuthService]
providers: [
AuthService,
{
provide: ConfigService,
useValue: {
get: jest.fn((key: string) => {
// this is being super extra, in the case that you need multiple keys with the `get` method
if (key === 'JWT_ACCESS_TOKEN_EXPIRATION_TIME') {
return 123
}
if (key === 'JWT_REFRESH_TOKEN_EXPIRATION_TIME') {
return 123
}
return null
})
}
}
]
})
.useMocker(token => {
if (Object.is(token, UserService)) {
Expand All @@ -35,6 +54,14 @@ describe('AuthService', () => {
if (Object.is(token, ConfirmCodeService)) {
return createMock<ConfirmCodeService>()
}

if (Object.is(token, OrganizationService)) {
return createMock<OrganizationService>()
}

if (Object.is(token, ConfigService)) {
return createMock<ConfigService>()
}
})
.compile()

Expand Down Expand Up @@ -90,6 +117,7 @@ describe('AuthService', () => {
checkPassword: jest.fn().mockResolvedValue(true)
})
)
mockedJwtService.sign.mockReturnValue('j.w.t')
const user = await service.login(email, password)

expect(user).toHaveProperty('email', email)
Expand Down Expand Up @@ -164,9 +192,10 @@ describe('AuthService', () => {
it('should sign a new JWT', () => {
const user = createMock<UserEntity>({ email: '[email protected]' })

mockedJwtService.sign.mockReturnValueOnce('j.w.t')
const token = service.signToken(user)
mockedJwtService.sign.mockReturnValue('j.w.t')
const { refresh_token, access_token } = service.signToken(user)

expect(token).toEqual(expect.any(String))
expect(access_token).toEqual(expect.any(String))
expect(refresh_token).toEqual(expect.any(String))
})
})
Loading
Loading