From 4544b7209b11324d2cab734624548cccc26555be Mon Sep 17 00:00:00 2001 From: Vins Date: Wed, 20 Dec 2023 11:15:59 +0100 Subject: [PATCH 1/3] Whitelist ready --- src/app/api/idnot/UserController.ts | 29 +++++++++++++- .../20231220084359_whitelist/migration.sql | 16 ++++++++ src/common/databases/schema.prisma | 9 +++++ .../repositories/WhitelistRepository.ts | 39 +++++++++++++++++++ .../controller-pattern/BaseController.ts | 4 ++ .../WhitelistService/WhitelistService.ts | 14 +++++++ 6 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/common/databases/migrations/20231220084359_whitelist/migration.sql create mode 100644 src/common/repositories/WhitelistRepository.ts create mode 100644 src/services/common/WhitelistService/WhitelistService.ts diff --git a/src/app/api/idnot/UserController.ts b/src/app/api/idnot/UserController.ts index 60d13059..77d79065 100644 --- a/src/app/api/idnot/UserController.ts +++ b/src/app/api/idnot/UserController.ts @@ -5,11 +5,14 @@ import { Service } from "typedi"; import AuthService, { IUserJwtPayload } from "@Services/common/AuthService/AuthService"; import IdNotService from "@Services/common/IdNotService/IdNotService"; +import WhitelistService from "@Services/common/WhitelistService/WhitelistService"; +import User from "le-coffre-resources/dist/SuperAdmin"; +import UsersService from "@Services/super-admin/UsersService/UsersService"; @Controller() @Service() export default class UserController extends ApiController { - constructor(private authService: AuthService, private idNotService: IdNotService) { + constructor(private authService: AuthService, private idNotService: IdNotService, private whitelistService: WhitelistService, private userService: UsersService) { super(); } @@ -25,6 +28,7 @@ export default class UserController extends ApiController { if (!code) throw new Error("code is required"); const idNotToken = await this.idNotService.getIdNotToken(code); + if(!idNotToken) { this.httpValidationError(response, "IdNot token undefined"); return; @@ -35,7 +39,28 @@ export default class UserController extends ApiController { this.httpUnauthorized(response); return; } - await this.idNotService.updateUser(user.uid); + + //Whitelist feature + //Get user with contact + const prismaUser = await this.userService.getByUid(user.uid, {contact: true }); + if (!prismaUser) { + this.httpNotFoundRequest(response, "user not found"); + return; + } + + //Hydrate user to be able to use his contact + const userHydrated = User.hydrate(prismaUser, { strategy: "excludeAll" }); + + //Check if user is whitelisted + const isWhitelisted = await this.whitelistService.getByEmail(userHydrated.contact!.email); + + //If not whitelisted, return 409 Not whitelisted + if (!isWhitelisted) { + this.httpNotWhitelisted(response); + return; + } + + await this.idNotService.updateUser(user.uid); await this.idNotService.updateOffice(user.office_uid); const payload = await this.authService.getUserJwtPayload(user.idNot); diff --git a/src/common/databases/migrations/20231220084359_whitelist/migration.sql b/src/common/databases/migrations/20231220084359_whitelist/migration.sql new file mode 100644 index 00000000..3a252b3e --- /dev/null +++ b/src/common/databases/migrations/20231220084359_whitelist/migration.sql @@ -0,0 +1,16 @@ +-- CreateTable +CREATE TABLE "whitelist" ( + "uid" TEXT NOT NULL, + "email" VARCHAR(255) NOT NULL, + "active" BOOLEAN NOT NULL DEFAULT true, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + + CONSTRAINT "whitelist_pkey" PRIMARY KEY ("uid") +); + +-- CreateIndex +CREATE UNIQUE INDEX "whitelist_uid_key" ON "whitelist"("uid"); + +-- CreateIndex +CREATE UNIQUE INDEX "whitelist_email_key" ON "whitelist"("email"); diff --git a/src/common/databases/schema.prisma b/src/common/databases/schema.prisma index 9d72ec44..de4afe97 100644 --- a/src/common/databases/schema.prisma +++ b/src/common/databases/schema.prisma @@ -72,6 +72,15 @@ model Users { @@map("users") } +model Whitelist { + uid String @id @unique @default(uuid()) + email String @unique @db.VarChar(255) + active Boolean @default(true) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + @@map("whitelist") +} + model Offices { uid String @id @unique @default(uuid()) idNot String @unique @db.VarChar(255) diff --git a/src/common/repositories/WhitelistRepository.ts b/src/common/repositories/WhitelistRepository.ts new file mode 100644 index 00000000..5f26c087 --- /dev/null +++ b/src/common/repositories/WhitelistRepository.ts @@ -0,0 +1,39 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { Prisma } from "prisma/prisma-client"; + +@Service() +export default class WhitelistRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().whitelist; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Find many whitelist + */ + public async findMany(query: Prisma.WhitelistFindManyArgs) { + query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + return this.model.findMany(query); + } + + /** + * @description : find unique by email + */ + public async findOneByEmail(email: string) { + return this.model.findUnique({ + where: { + email: email, + }, + }); + } + + + +} diff --git a/src/common/system/controller-pattern/BaseController.ts b/src/common/system/controller-pattern/BaseController.ts index 0e5003cc..0603c480 100644 --- a/src/common/system/controller-pattern/BaseController.ts +++ b/src/common/system/controller-pattern/BaseController.ts @@ -48,6 +48,10 @@ export default abstract class BaseController { return this.httpResponse(response, HttpCodes.FORBIDDEN, responseData); } + protected httpNotWhitelisted(response: Response, responseData: IResponseData = "Not whitelisted") { + return this.httpResponse(response, HttpCodes.VALIDATION_ERROR, responseData); + } + protected httpResponse(response: Response, httpCode: HttpCodes, responseData: IResponseData = {}) { if (responseData instanceof Error) { throw responseData; diff --git a/src/services/common/WhitelistService/WhitelistService.ts b/src/services/common/WhitelistService/WhitelistService.ts new file mode 100644 index 00000000..9e98a35e --- /dev/null +++ b/src/services/common/WhitelistService/WhitelistService.ts @@ -0,0 +1,14 @@ +import WhitelistRepository from "@Repositories/WhitelistRepository"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; + +@Service() +export default class WhitelistService extends BaseService { + constructor(private whitelistRepository: WhitelistRepository) { + super(); + } + + public async getByEmail(email: string): Promise { + return this.whitelistRepository.findOneByEmail(email); + } +} From 2f4bd04ab3669add179727e6bb18cc00e436afba Mon Sep 17 00:00:00 2001 From: Vins Date: Wed, 20 Dec 2023 15:07:59 +0100 Subject: [PATCH 2/3] email not found error --- src/app/api/idnot/UserController.ts | 10 +++++++++- src/services/common/IdNotService/IdNotService.ts | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/app/api/idnot/UserController.ts b/src/app/api/idnot/UserController.ts index 77d79065..f614b419 100644 --- a/src/app/api/idnot/UserController.ts +++ b/src/app/api/idnot/UserController.ts @@ -33,7 +33,15 @@ export default class UserController extends ApiController { this.httpValidationError(response, "IdNot token undefined"); return; } - const user = await this.idNotService.getOrCreateUser(idNotToken); + + let user; + + try { + user = await this.idNotService.getOrCreateUser(idNotToken); + } catch (error: any) { + this.httpUnauthorized(error); + return; + } if(!user) { this.httpUnauthorized(response); diff --git a/src/services/common/IdNotService/IdNotService.ts b/src/services/common/IdNotService/IdNotService.ts index 5f9f9fda..edc58508 100644 --- a/src/services/common/IdNotService/IdNotService.ts +++ b/src/services/common/IdNotService/IdNotService.ts @@ -359,6 +359,10 @@ export default class IdNotService extends BaseService { updated_at: null, }, }; + + if(!userToAdd.contact.email) { + throw new Error("No email found"); + } let userHydrated = User.hydrate(userToAdd); const user = await this.userService.create(userHydrated); From 7031bb1d4888c698d0c26966815ce89c2c56f77e Mon Sep 17 00:00:00 2001 From: Vins Date: Wed, 20 Dec 2023 15:14:03 +0100 Subject: [PATCH 3/3] Email not found error returned correctyl --- src/app/api/idnot/UserController.ts | 11 ++--------- src/services/common/IdNotService/IdNotService.ts | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/app/api/idnot/UserController.ts b/src/app/api/idnot/UserController.ts index f614b419..8b448b2b 100644 --- a/src/app/api/idnot/UserController.ts +++ b/src/app/api/idnot/UserController.ts @@ -34,17 +34,10 @@ export default class UserController extends ApiController { return; } - let user; - - try { - user = await this.idNotService.getOrCreateUser(idNotToken); - } catch (error: any) { - this.httpUnauthorized(error); - return; - } + const user = await this.idNotService.getOrCreateUser(idNotToken); if(!user) { - this.httpUnauthorized(response); + this.httpUnauthorized(response, "Email not found"); return; } diff --git a/src/services/common/IdNotService/IdNotService.ts b/src/services/common/IdNotService/IdNotService.ts index edc58508..eca8fe37 100644 --- a/src/services/common/IdNotService/IdNotService.ts +++ b/src/services/common/IdNotService/IdNotService.ts @@ -361,7 +361,7 @@ export default class IdNotService extends BaseService { }; if(!userToAdd.contact.email) { - throw new Error("No email found"); + return null; } let userHydrated = User.hydrate(userToAdd);