Skip to content

Commit

Permalink
feat(server): support auth methods of email (labring#1867)
Browse files Browse the repository at this point in the history
* feat(server): support email auth
  • Loading branch information
0fatal authored Feb 22, 2024
1 parent 9f0a683 commit 2364f57
Show file tree
Hide file tree
Showing 9 changed files with 422 additions and 32 deletions.
51 changes: 51 additions & 0 deletions server/src/authentication/dto/email-signin.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
import {
IsNotEmpty,
IsString,
Length,
IsOptional,
Matches,
IsEmail,
} from 'class-validator'

export class EmailSigninDto {
@ApiProperty({
description: 'email',
})
@IsString()
@IsNotEmpty()
@IsEmail()
email: string

@ApiProperty({})
@IsNotEmpty()
@Length(6, 6)
code: string

@ApiProperty({
description: 'username',
example: 'laf-user',
})
@IsOptional()
@IsString()
@Length(3, 64)
username: string

@ApiProperty({
description: 'password, 8-64 characters',
example: 'laf-user-password',
})
@IsOptional()
@IsString()
@Length(8, 64)
password: string

@ApiPropertyOptional({
description: 'invite code',
example: 'iLeMi7x',
})
@IsOptional()
@IsString()
@Matches(/^\S+$/, { message: 'invalid characters' })
inviteCode: string
}
26 changes: 17 additions & 9 deletions server/src/authentication/dto/passwd-reset.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { ApiProperty } from '@nestjs/swagger'
import { IsEnum, IsNotEmpty, IsString, Length, Matches } from 'class-validator'
import { SmsVerifyCodeType } from '../entities/sms-verify-code'
import {
IsEmail,
IsNotEmpty,
IsOptional,
IsString,
Length,
Matches,
} from 'class-validator'

export class PasswdResetDto {
@ApiProperty({
Expand All @@ -17,21 +23,23 @@ export class PasswdResetDto {
example: '13805718888',
})
@IsString()
@IsOptional()
@Matches(/^1[3-9]\d{9}$/)
phone: string

@ApiProperty({
description: 'email',
})
@IsString()
@IsEmail()
@IsOptional()
email: string

@ApiProperty({
description: 'verify code',
example: '032456',
})
@IsString()
@Length(6, 6)
code: string

@ApiProperty({
description: 'type',
example: 'ResetPassword',
})
@IsEnum(SmsVerifyCodeType)
type: SmsVerifyCodeType
}
19 changes: 9 additions & 10 deletions server/src/authentication/dto/passwd-signup.dto.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
import {
IsEnum,
IsEmail,
IsNotEmpty,
IsOptional,
IsString,
Length,
Matches,
} from 'class-validator'
import { SmsVerifyCodeType } from '../entities/sms-verify-code'

export class PasswdSignupDto {
@ApiProperty({
Expand Down Expand Up @@ -40,21 +39,21 @@ export class PasswdSignupDto {
phone: string

@ApiPropertyOptional({
description: 'verify code',
example: '032456',
description: 'email',
})
@IsOptional()
@IsString()
@Length(6, 6)
code: string
@IsEmail()
email: string

@ApiPropertyOptional({
description: 'type',
example: 'Signup',
description: 'verify code',
example: '032456',
})
@IsOptional()
@IsEnum(SmsVerifyCodeType)
type: SmsVerifyCodeType
@IsString()
@Length(6, 6)
code: string

@ApiPropertyOptional({
description: 'invite code',
Expand Down
57 changes: 56 additions & 1 deletion server/src/authentication/email/email.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@ import { ResponseUtil } from 'src/utils/response'
import { SendEmailCodeDto } from '../dto/send-email-code.dto'
import { EmailService } from './email.service'
import { GetClientIPFromRequest } from 'src/utils/getter'
import { UserService } from 'src/user/user.service'
import { EmailSigninDto } from '../dto/email-signin.dto'
import { EmailVerifyCodeType } from '../entities/email-verify-code'
import { AuthenticationService } from '../authentication.service'
import { AuthBindingType, AuthProviderBinding } from '../entities/types'

@ApiTags('Authentication')
@Controller('auth')
export class EmailController {
private readonly logger = new Logger(EmailController.name)

constructor(private readonly emailService: EmailService) {}
constructor(
private readonly emailService: EmailService,
private readonly authService: AuthenticationService,
private readonly userService: UserService,
) {}

/**
* send email code
Expand All @@ -30,4 +39,50 @@ export class EmailController {
}
return ResponseUtil.ok('success')
}

/**
* Signin by email and verify code
*/
@ApiOperation({ summary: 'Signin by email and verify code' })
@ApiResponse({ type: ResponseUtil })
@Post('email/signin')
async signin(@Body() dto: EmailSigninDto) {
const { email, code } = dto
// check if code valid
const err = await this.emailService.validateCode(
email,
code,
EmailVerifyCodeType.Signin,
)
if (err) return ResponseUtil.error(err)

// check if user exists
const user = await this.userService.findOneByEmail(email)
if (user) {
const token = this.emailService.signin(user)
return ResponseUtil.ok(token)
}

// user not exist
const provider = await this.authService.getEmailProvider()
if (provider.register === false) {
return ResponseUtil.error('user not exists')
}

// check if username and password is needed
let signupWithUsername = false
const bind = provider.bind as any as AuthProviderBinding
if (bind.username === AuthBindingType.Required) {
const { username, password } = dto
signupWithUsername = true
if (!username || !password) {
return ResponseUtil.error('username and password is required')
}
}

// user not exist, signup and signin
const newUser = await this.emailService.signup(dto, signupWithUsername)
const data = this.emailService.signin(newUser)
return ResponseUtil.ok(data)
}
}
Loading

0 comments on commit 2364f57

Please sign in to comment.