From f128c7fccbfde0e8ea262cc5f205951b4922d00d Mon Sep 17 00:00:00 2001 From: Adelina Enache Date: Sun, 19 May 2024 10:46:27 +0300 Subject: [PATCH] feat: auth flow changes (#73) * Add joined at date for searched user * Update user search query to respect respect http standards * Enable cors * minor fixes * Correct relations * Check if users are connected when doing an user search * fix db structure * fix namings * Use passwordless signup * Return props needed for signin redirection --- src/auth/auth.e2e.spec.ts | 23 ++-------------- src/auth/controller/auth.controller.ts | 15 +++++------ src/auth/dto/signin.dto.ts | 11 +------- src/auth/dto/signup.dto.ts | 15 +---------- src/auth/service/auth.service.ts | 27 +++++-------------- .../migration.sql | 8 ++++++ src/prisma/schema.prisma | 1 - 7 files changed, 24 insertions(+), 76 deletions(-) create mode 100644 src/prisma/migrations/20240509140026_drop_password/migration.sql diff --git a/src/auth/auth.e2e.spec.ts b/src/auth/auth.e2e.spec.ts index 5153bcf..0f6f701 100644 --- a/src/auth/auth.e2e.spec.ts +++ b/src/auth/auth.e2e.spec.ts @@ -39,39 +39,23 @@ describe('Auth Controller Tests', () => { expect(prisma).toBeDefined(); }); - it('should fail sign up if password does not meet requirements', async () => { - const response = await app.inject({ - method: 'POST', - url: '/auth/sign-up', - payload: { - email: 'janedoe@example.com', - password: 'password', - }, - }); - - expect(response.statusCode).toEqual(400); - }); - - it('should be able to sign up using email and password', async () => { + it('should be able to sign up using email', async () => { const response = await app.inject({ method: 'POST', url: '/auth/sign-up', payload: { email: 'jane@example.com', - password: 'Password123', }, }); expect(response.statusCode).toEqual(201); expect(response.json().email).toEqual('jane@example.com'); - expect(response.json().password).toBeUndefined(); }); - it('should be able to sign in using email and password', async () => { + it('should be able to sign in using email', async () => { await prisma.user.create({ data: { email: 'jane@example.com', - password: SHA256('password').toString(), isEmailVerified: true, authType: AuthType.EMAIL, }, @@ -82,14 +66,11 @@ describe('Auth Controller Tests', () => { url: '/auth/sign-in', payload: { email: 'jane@example.com', - password: 'password', }, }); expect(response.statusCode).toEqual(201); expect(response.json().email).toEqual('jane@example.com'); - expect(response.json().password).toBeUndefined(); - expect(response.json().token).toBeDefined(); }); it('should send verification code to email on sign up', async () => { diff --git a/src/auth/controller/auth.controller.ts b/src/auth/controller/auth.controller.ts index f076953..3cd3932 100644 --- a/src/auth/controller/auth.controller.ts +++ b/src/auth/controller/auth.controller.ts @@ -7,6 +7,7 @@ import { HttpStatus, Param, Post, + Put, Req, Res, UseGuards, @@ -29,7 +30,6 @@ import { ApiNotFoundResponse, ApiOperation, ApiTags, - ApiUnauthorizedResponse, } from '@nestjs/swagger'; import { userProperties } from '../../schemas/user.properties'; @@ -144,7 +144,7 @@ export class AuthController { @Post('sign-up') @ApiOperation({ summary: 'Sign up', - description: 'Sign up with email and password', + description: 'Sign up with email', }) @ApiCreatedResponse({ description: 'User signed up successfully', @@ -160,21 +160,18 @@ export class AuthController { @Post('sign-in') @ApiOperation({ summary: 'Sign in', - description: 'Sign in with email and password', + description: 'Sign in with email', }) @ApiNotFoundResponse({ description: 'User not found', }) - @ApiUnauthorizedResponse({ - description: 'Invalid password', - }) @ApiCreatedResponse({ description: 'User signed in successfully', schema: { type: 'object', properties: { - ...userProperties, - token: { type: 'string' }, + isEmailVerified: userProperties.isEmailVerified, + email: userProperties.email, }, }, }) @@ -183,7 +180,7 @@ export class AuthController { } @Public() - @Get('regenerate-code/:email') + @Put('regenerate-code/:email') @ApiOperation({ summary: 'Resend email verification code', description: 'Resend email verification code to the user', diff --git a/src/auth/dto/signin.dto.ts b/src/auth/dto/signin.dto.ts index 9c210e0..da1a652 100644 --- a/src/auth/dto/signin.dto.ts +++ b/src/auth/dto/signin.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsEmail, IsString } from 'class-validator'; +import { IsEmail } from 'class-validator'; export class SigninDto { @IsEmail() @@ -11,13 +11,4 @@ export class SigninDto { example: 'johndoe@example.com', }) email: string; - @IsString() - @ApiProperty({ - name: 'password', - description: 'User password. Must be a string.', - required: true, - type: String, - example: 'password123', - }) - password: string; } diff --git a/src/auth/dto/signup.dto.ts b/src/auth/dto/signup.dto.ts index b580dd5..ea04a40 100644 --- a/src/auth/dto/signup.dto.ts +++ b/src/auth/dto/signup.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsEmail, Matches } from 'class-validator'; +import { IsEmail } from 'class-validator'; export class SignupDto { @IsEmail() @@ -11,17 +11,4 @@ export class SignupDto { example: 'johndoe@example.com', }) email: string; - @Matches(/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{9,}$/, { - message: - 'Password must contain at least 1 letter, 1 number and be at least 9 characters long', - }) - @ApiProperty({ - name: 'password', - description: - 'User password. Must contain at least 1 letter, 1 number and be at least 9 characters long.', - required: true, - type: String, - example: 'password123', - }) - password: string; } diff --git a/src/auth/service/auth.service.ts b/src/auth/service/auth.service.ts index e60b8c3..3ba523c 100644 --- a/src/auth/service/auth.service.ts +++ b/src/auth/service/auth.service.ts @@ -3,20 +3,14 @@ import { ConflictException, Injectable, NotFoundException, - UnauthorizedException, } from '@nestjs/common'; import { PrismaService } from '../../prisma/prisma.service'; import { JwtService } from '@nestjs/jwt'; import { AuthType, User } from '@prisma/client'; import { SignupDto } from '../dto/signup.dto'; -import { SHA256 } from 'crypto-js'; import { MailService } from '../../mail/mail.service'; import { SigninDto } from '../dto/signin.dto'; -function hashPassword(password: string) { - return SHA256(password).toString(); -} - @Injectable() export class AuthService { constructor( @@ -31,7 +25,6 @@ export class AuthService { AuthType.EMAIL, null, null, - hashPassword(dto.password), true, ); @@ -43,24 +36,18 @@ export class AuthService { where: { email: dto.email, }, + select: { + isEmailVerified: true, + email: true, + }, }); if (!user) { throw new NotFoundException('User not found'); } - if (user.password !== hashPassword(dto.password)) { - throw new UnauthorizedException('Invalid password'); - } - - user.password = undefined; - - const token = await this.generateToken(user); - - return { - ...user, - token, - }; + await this.sendEmailVerificationCode(dto.email); + return user; } async handleGoogleOAuthLogin(req: any) { @@ -212,7 +199,6 @@ export class AuthService { authType: AuthType, name?: string, profilePictureUrl?: string, - password?: string, throwErrorIfUserExists?: boolean, ) { let user = await this.findUserByEmail(email); @@ -227,7 +213,6 @@ export class AuthService { name: name, profilePictureUrl: profilePictureUrl, authType, - password, }, select: { id: true, diff --git a/src/prisma/migrations/20240509140026_drop_password/migration.sql b/src/prisma/migrations/20240509140026_drop_password/migration.sql new file mode 100644 index 0000000..af084ae --- /dev/null +++ b/src/prisma/migrations/20240509140026_drop_password/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - You are about to drop the column `password` on the `User` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "User" DROP COLUMN "password"; diff --git a/src/prisma/schema.prisma b/src/prisma/schema.prisma index e496f7a..1510ffb 100644 --- a/src/prisma/schema.prisma +++ b/src/prisma/schema.prisma @@ -18,7 +18,6 @@ enum AuthType { model User { id String @id @default(cuid()) email String @unique - password String? name String? profilePictureUrl String? socialAccounts UserSocialAccount[]