Skip to content

Commit

Permalink
feat: add verify feature
Browse files Browse the repository at this point in the history
  • Loading branch information
tnramalho committed Dec 13, 2024
1 parent 567819a commit c64427f
Show file tree
Hide file tree
Showing 50 changed files with 2,306 additions and 425 deletions.
15 changes: 15 additions & 0 deletions packages/nestjs-auth-verify/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Rockets NestJS Auth verify Authentication

Verify user password using email

## Project

[![NPM Latest](https://img.shields.io/npm/v/@concepta/nestjs-auth-verify)](https://www.npmjs.com/package/@concepta/nestjs-auth-verify)
[![NPM Downloads](https://img.shields.io/npm/dw/@conceptadev/nestjs-auth-verify)](https://www.npmjs.com/package/@concepta/nestjs-auth-verify)
[![GH Last Commit](https://img.shields.io/github/last-commit/conceptadev/rockets?logo=github)](https://github.com/conceptadev/rockets)
[![GH Contrib](https://img.shields.io/github/contributors/conceptadev/rockets?logo=github)](https://github.com/conceptadev/rockets/graphs/contributors)
[![NestJS Dep](https://img.shields.io/github/package-json/dependency-version/conceptadev/rockets/@nestjs/common?label=NestJS&logo=nestjs&filename=packages%2Fnestjs-core%2Fpackage.json)](https://www.npmjs.com/package/@nestjs/common)

## Installation

`yarn add @concepta/nestjs-auth-verify`
44 changes: 44 additions & 0 deletions packages/nestjs-auth-verify/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "@concepta/nestjs-auth-verify",
"version": "5.1.0",
"description": "Rockets NestJS Auth Recovery",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "BSD-3-Clause",
"publishConfig": {
"access": "public"
},
"files": [
"dist/**/!(*.spec|*.e2e-spec|*.fixture).{js,d.ts}"
],
"dependencies": {
"@concepta/nestjs-common": "^5.1.0",
"@concepta/typeorm-common": "^5.1.0",
"@nestjs/common": "^10.4.1",
"@nestjs/config": "^3.2.3",
"@nestjs/core": "^10.4.1",
"@nestjs/swagger": "^7.4.0"
},
"devDependencies": {
"@concepta/nestjs-auth-jwt": "^5.1.0",
"@concepta/nestjs-authentication": "^5.1.0",
"@concepta/nestjs-crud": "^5.1.0",
"@concepta/nestjs-email": "^5.1.0",
"@concepta/nestjs-jwt": "^5.1.0",
"@concepta/nestjs-otp": "^5.1.0",
"@concepta/nestjs-password": "^5.1.0",
"@concepta/nestjs-typeorm-ext": "^5.1.0",
"@concepta/nestjs-user": "^5.1.0",
"@concepta/typeorm-seeding": "^4.0.0",
"@nestjs/testing": "^10.4.1",
"@nestjs/typeorm": "^10.0.2",
"jest-mock-extended": "^2.0.9",
"supertest": "^6.3.4"
},
"peerDependencies": {
"class-transformer": "*",
"class-validator": "*",
"rxjs": "^7.1.0",
"typeorm": "^0.3.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Module } from '@nestjs/common';

import { TypeOrmExtModule } from '@concepta/nestjs-typeorm-ext';
import { CrudModule } from '@concepta/nestjs-crud';
import { PasswordModule } from '@concepta/nestjs-password';
import { AuthenticationModule } from '@concepta/nestjs-authentication';
import { JwtModule } from '@concepta/nestjs-jwt';
import { AuthJwtModule } from '@concepta/nestjs-auth-jwt';
import { OtpModule, OtpService } from '@concepta/nestjs-otp';
import { EmailModule, EmailService } from '@concepta/nestjs-email';
import {
UserLookupService,
UserModule,
UserMutateService,
} from '@concepta/nestjs-user';

import { AuthVerifyModule } from '../auth-verify.module';
import { UserOtpEntityFixture } from './user/entities/user-otp-entity.fixture';
import { UserEntityFixture } from './user/entities/user-entity.fixture';

import { default as ormConfig } from './ormconfig.fixture';
import { MailerServiceFixture } from './email/mailer.service.fixture';

@Module({
imports: [
TypeOrmExtModule.forRoot(ormConfig),
CrudModule.forRoot({}),
JwtModule.forRoot({}),
AuthenticationModule.forRoot({
settings: {
disableGuard: (context, guard) =>
guard.constructor.name === 'AuthJwtGuard' &&
context.getClass().name === 'UserController',
},
}),
AuthJwtModule.forRootAsync({
inject: [UserLookupService],
useFactory: (userLookupService: UserLookupService) => ({
userLookupService,
}),
}),
AuthVerifyModule.forRootAsync({
inject: [UserLookupService, UserMutateService, OtpService, EmailService],
useFactory: (
userLookupService,
userMutateService,
otpService,
emailService,
) => ({
userLookupService,
userMutateService,
otpService,
emailService,
}),
}),
OtpModule.forRoot({
entities: {
userOtp: {
entity: UserOtpEntityFixture,
},
},
}),
PasswordModule.forRoot({}),
UserModule.forRoot({
entities: {
user: {
entity: UserEntityFixture,
},
},
}),
EmailModule.forRoot({
mailerService: new MailerServiceFixture(),
}),
],
})
export class AppModuleDbFixture {}
52 changes: 52 additions & 0 deletions packages/nestjs-auth-verify/src/__fixtures__/app.module.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Module } from '@nestjs/common';
import { EmailModule, EmailService } from '@concepta/nestjs-email';
import { AuthenticationModule } from '@concepta/nestjs-authentication';
import { AuthJwtModule } from '@concepta/nestjs-auth-jwt';
import { JwtModule } from '@concepta/nestjs-jwt';

import { AuthVerifyModule } from '../auth-verify.module';

import { TypeOrmModuleFixture } from './typeorm.module.fixture';
import { OtpServiceFixture } from './otp/otp.service.fixture';
import { UserLookupServiceFixture } from './user/services/user-lookup.service.fixture';
import { UserMutateServiceFixture } from './user/services/user-mutate.service.fixture';
import { UserModuleFixture } from './user/user.module.fixture';
import { OtpModuleFixture } from './otp/otp.module.fixture';
import { MailerServiceFixture } from './email/mailer.service.fixture';

@Module({
imports: [
TypeOrmModuleFixture,
JwtModule.forRoot({}),
AuthenticationModule.forRoot({}),
AuthJwtModule.forRootAsync({
inject: [UserLookupServiceFixture],
useFactory: (userLookupService: UserLookupServiceFixture) => ({
userLookupService,
}),
}),
AuthVerifyModule.forRootAsync({
inject: [
EmailService,
OtpServiceFixture,
UserLookupServiceFixture,
UserMutateServiceFixture,
],
useFactory: (
emailService,
otpService,
userLookupService,
userMutateService,
) => ({
emailService,
otpService,
userLookupService,
userMutateService,
}),
}),
EmailModule.forRoot({ mailerService: new MailerServiceFixture() }),
OtpModuleFixture,
UserModuleFixture,
],
})
export class AppModuleFixture {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Injectable } from '@nestjs/common';
import {
EmailSendInterface,
EmailSendOptionsInterface,
} from '@concepta/nestjs-common';

@Injectable()
export class MailerServiceFixture implements EmailSendInterface {
sendMail(_sendMailOptions: EmailSendOptionsInterface): Promise<void> {
throw new Error('Method not implemented.');
}
}
12 changes: 12 additions & 0 deletions packages/nestjs-auth-verify/src/__fixtures__/ormconfig.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { DataSourceOptions } from 'typeorm';
import { UserOtpEntityFixture } from './user/entities/user-otp-entity.fixture';
import { UserEntityFixture } from './user/entities/user-entity.fixture';

const config: DataSourceOptions = {
type: 'sqlite',
database: ':memory:',
synchronize: true,
entities: [UserEntityFixture, UserOtpEntityFixture],
};

export default config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Global, Module } from '@nestjs/common';
import { OtpServiceFixture } from './otp.service.fixture';

@Global()
@Module({
providers: [OtpServiceFixture],
exports: [OtpServiceFixture],
})
export class OtpModuleFixture {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { randomUUID } from 'crypto';
import { Injectable } from '@nestjs/common';

import {
OtpCreatableInterface,
OtpInterface,
ReferenceAssigneeInterface,
ReferenceIdInterface,
} from '@concepta/nestjs-common';

import { AuthVerifyOtpServiceInterface } from '../../interfaces/auth-verify-otp.service.interface';
import { UserFixture } from '../user/user.fixture';

@Injectable()
export class OtpServiceFixture implements AuthVerifyOtpServiceInterface {
async create(
_assignment: string,
otp: OtpCreatableInterface,
): Promise<OtpInterface> {
const { assignee, category, type } = otp;
return {
id: randomUUID(),
category,
type,
assignee,
passcode: 'GOOD_PASSCODE',
expirationDate: new Date(),
dateCreated: new Date(),
dateUpdated: new Date(),
dateDeleted: null,
version: 1,
};
}

async validate(
_assignment: string,
otp: Pick<OtpInterface, 'category' | 'passcode'>,
_deleteIfValid: boolean,
): Promise<ReferenceAssigneeInterface<ReferenceIdInterface<string>> | null> {
return otp.passcode === 'GOOD_PASSCODE' ? { assignee: UserFixture } : null;
}

async clear(
_assignment: string,
_otp: Pick<OtpInterface, 'category' | 'assignee'>,
): Promise<void> {
return;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Global, Module } from '@nestjs/common';
import { getEntityManagerToken } from '@nestjs/typeorm';
import { createEntityManagerMock } from '@concepta/typeorm-common';

@Global()
@Module({
providers: [
{
provide: getEntityManagerToken(),
useFactory: createEntityManagerMock,
},
],
exports: [getEntityManagerToken()],
})
export class TypeOrmModuleFixture {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Entity, OneToMany } from 'typeorm';
import { UserSqliteEntity } from '@concepta/nestjs-user';
import { UserOtpEntityFixture } from './user-otp-entity.fixture';

/**
* User Entity Fixture
*/
@Entity()
export class UserEntityFixture extends UserSqliteEntity {
@OneToMany(() => UserOtpEntityFixture, (userOtp) => userOtp.assignee)
userOtps?: UserOtpEntityFixture[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Column, Entity, ManyToOne } from 'typeorm';
import { ReferenceIdInterface } from '@concepta/nestjs-common';
import { UserEntityFixture } from './user-entity.fixture';
import { OtpInterface } from '@concepta/nestjs-common';
import { CommonSqliteEntity } from '@concepta/typeorm-common';

/**
* Otp Entity Fixture
*/
@Entity()
export class UserOtpEntityFixture
extends CommonSqliteEntity
implements OtpInterface
{
@Column()
category!: string;

@Column({ nullable: true })
type!: string;

@Column()
passcode!: string;

@Column({ type: 'datetime' })
expirationDate!: Date;

@ManyToOne(() => UserEntityFixture, (user) => user.userOtps)
assignee!: ReferenceIdInterface;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Injectable } from '@nestjs/common';
import {
ReferenceEmail,
ReferenceIdInterface,
ReferenceSubject,
} from '@concepta/nestjs-common';

import { AuthVerifyUserLookupServiceInterface } from '../../../interfaces/auth-verify-user-lookup.service.interface';

import { UserFixture } from '../user.fixture';

@Injectable()
export class UserLookupServiceFixture
implements AuthVerifyUserLookupServiceInterface
{
async byId(
id: string,
): ReturnType<AuthVerifyUserLookupServiceInterface['byId']> {
if (id === UserFixture.id) {
return UserFixture;
} else {
throw new Error();
}
}

async byEmail(
email: ReferenceEmail,
): ReturnType<AuthVerifyUserLookupServiceInterface['byEmail']> {
return email === UserFixture.email ? UserFixture : null;
}

async bySubject(subject: ReferenceSubject): Promise<ReferenceIdInterface> {
throw new Error(`Method not implemented, can't get ${subject}.`);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Injectable } from '@nestjs/common';
import {
ReferenceActiveInterface,
ReferenceIdInterface,
} from '@concepta/nestjs-common';

import { AuthVerifyUserMutateServiceInterface } from '../../../interfaces/auth-verify-user-mutate.service.interface';

import { UserFixture } from '../user.fixture';

@Injectable()
export class UserMutateServiceFixture
implements AuthVerifyUserMutateServiceInterface
{
// ReferenceIdInterface & ReferenceActiveInterface,
// ReferenceIdInterface & ReferenceEmailInterface & ReferenceActiveInterface,
async update(
object: ReferenceIdInterface<string> & ReferenceActiveInterface,
): ReturnType<AuthVerifyUserMutateServiceInterface['update']> {
if (object.id === UserFixture.id) {
return UserFixture;
} else {
throw new Error();
}
}
}
Loading

0 comments on commit c64427f

Please sign in to comment.