From 63c0b092dcf65b862a58e262f8acbb021eb4093c Mon Sep 17 00:00:00 2001 From: Kevin Barnoin Date: Mon, 27 Nov 2023 16:56:18 +0100 Subject: [PATCH] feat: remove password (#860) * feat: remove password * fix: type * chore: fix preview * chore: fix preview deployment --------- Co-authored-by: Moroine Bentefrit --- .infra/ansible/preview.yml | 2 +- .talismanrc | 2 + .../common/model/schema/user/user.schema.ts | 5 -- .../common/model/schema/user/user.types.ts | 1 - .../20231127120528-remove-password.ts | 18 ++++++ .../routes/appointmentRequest.controller.ts | 2 +- server/src/services/user.service.ts | 61 +------------------ server/src/services/userRecruteur.service.ts | 4 +- server/tests/integration/common/users.test.ts | 34 ++--------- 9 files changed, 31 insertions(+), 98 deletions(-) create mode 100644 server/src/db/migrations/20231127120528-remove-password.ts diff --git a/.infra/ansible/preview.yml b/.infra/ansible/preview.yml index d0fc21c331..bae2b66e5f 100644 --- a/.infra/ansible/preview.yml +++ b/.infra/ansible/preview.yml @@ -15,7 +15,7 @@ - name: Setup MongoDB ReplicaSet shell: chdir: /opt/app - cmd: 'docker compose exec -it mongodb mongosh --eval "try { rs.status().ok } catch (e) { if (e.code === 94) {rs.initiate();} else {throw e} }" --quiet' + cmd: 'docker compose -f docker-compose.preview-system.yml exec -it mongodb mongosh "{{ vault[env_type].LBA_MONGODB_URI }}" --eval "try { rs.status().ok } catch (e) { if (e.code === 94) {rs.initiate();} else {throw e} }" --quiet' when: env_type == 'preview' - include_tasks: ./tasks/preview_pr.yml diff --git a/.talismanrc b/.talismanrc index 73cb0dee15..9cb8bad726 100644 --- a/.talismanrc +++ b/.talismanrc @@ -39,6 +39,8 @@ fileignoreconfig: checksum: b6762a7cb5df9bbee1f0ce893827f0991ad01514f7122a848b3b5d49b620f238 - filename: server/src/config.ts checksum: 0a7fb0cc67e8d1453b1605840a2ff848466c640557e315929002833c10f58812 +- filename: server/src/db/migrations/20231127120528-remove-password.ts + checksum: 5c7a2ec4655f0543f42bfbccc759bff4eb10456946885531c91107cac3e8dbc0 - filename: server/src/http/controllers/appointments/appointments.controller.ts checksum: dc77c04efc26dcd8ca4816f392ab24a32a92cb45ca4b94adb593a08e7a2d231e - filename: server/src/http/routes/appointmentRequest.controller.ts diff --git a/server/src/common/model/schema/user/user.schema.ts b/server/src/common/model/schema/user/user.schema.ts index 9bdcfaa846..1632325d7a 100644 --- a/server/src/common/model/schema/user/user.schema.ts +++ b/server/src/common/model/schema/user/user.schema.ts @@ -11,11 +11,6 @@ export const userSchema = new Schema( description: "Le nom de l'utilisateur", unique: true, }, - password: { - type: String, - default: null, - description: "Le mot de passe hashé", - }, firstname: { type: String, default: null, diff --git a/server/src/common/model/schema/user/user.types.ts b/server/src/common/model/schema/user/user.types.ts index 13697b3efa..39e6faf8db 100644 --- a/server/src/common/model/schema/user/user.types.ts +++ b/server/src/common/model/schema/user/user.types.ts @@ -3,7 +3,6 @@ import { ObjectId } from "mongodb" export interface IUser { _id: ObjectId username: string - password: string firstname: string lastname: string phone: string diff --git a/server/src/db/migrations/20231127120528-remove-password.ts b/server/src/db/migrations/20231127120528-remove-password.ts new file mode 100644 index 0000000000..2ead3bf525 --- /dev/null +++ b/server/src/db/migrations/20231127120528-remove-password.ts @@ -0,0 +1,18 @@ +import { Db } from "mongodb" + +import { logger } from "@/common/logger" + +export const up = async (db: Db) => { + await db.collection("users").updateMany( + {}, + { + $unset: { password: "" }, + }, + { + // @ts-expect-error bypassDocumentValidation is not properly set in @types/mongodb + bypassDocumentValidation: true, + } + ) + + logger.info("20231127120528-remove-password") +} diff --git a/server/src/http/routes/appointmentRequest.controller.ts b/server/src/http/routes/appointmentRequest.controller.ts index 02328697c7..fdd5a5f878 100644 --- a/server/src/http/routes/appointmentRequest.controller.ts +++ b/server/src/http/routes/appointmentRequest.controller.ts @@ -66,7 +66,7 @@ export default (server: Server) => { throw Boom.badRequest(`Une demande de prise de RDV en date du ${dayjs(appointment.created_at).format("DD/MM/YYYY")} est actuellement est cours de traitement.`) } } else { - user = await users.createUser(email, "NA", { + user = await users.createUser(email, { firstname, lastname, phone, diff --git a/server/src/services/user.service.ts b/server/src/services/user.service.ts index b8c0c16916..b72a7a0cd2 100644 --- a/server/src/services/user.service.ts +++ b/server/src/services/user.service.ts @@ -4,44 +4,6 @@ import { ETAT_UTILISATEUR } from "shared/constants/recruteur" import { Recruiter, User, UserRecruteur } from "../common/model/index" import { IUser } from "../common/model/schema/user/user.types" -import * as sha512Utils from "../common/utils/sha512Utils" - -/** - * @description Hash password - * @param {User} user - * @param {string} password - * @returns {Promise} - */ -const rehashPassword = (user, password: string) => { - user.password = sha512Utils.hash(password) - - return user.save() -} - -/** - * @description Authenticates user from its username and password. - * @param {string} username - * @param {string} password - * @returns {Promise} - */ -const authenticate = async (username: string, password: string): Promise => { - const user = await getUser(username) - - if (!user) { - return null - } - - const current = user.password - if (sha512Utils.compare(password, current)) { - if (sha512Utils.isTooWeak(current)) { - await rehashPassword(user, password) - } - - return user.toObject() - } - - return null -} /** * @description Returns user from its username. @@ -79,13 +41,11 @@ const update = (id: string, params) => User.findOneAndUpdate({ _id: id }, params * @param {User} options * @returns {Promise} */ -const createUser = async (username, password, options: Partial) => { - const hash = options.hash || sha512Utils.hash(password) +const createUser = async (username, options: Partial) => { const { firstname, lastname, phone, email, role, type } = options const user = new User({ username, - password: hash, firstname, lastname, phone, @@ -111,23 +71,6 @@ const find = (conditions: FilterQuery) => User.find(conditions) */ const findOne = (conditions: FilterQuery) => User.findOne(conditions) -/** - * @description Updates user's password. - * @param {string} username - * @param {string} newPassword - * @returns {Promise} - */ -const changePassword = async (username: string, newPassword: string) => { - const user = await User.findOne({ username }) - if (!user) { - throw new Error(`Unable to find user ${username}`) - } - - user.password = sha512Utils.hash(newPassword) - - return user.save() -} - type IUserRecruterPicked = Pick< IUserRecruteur, "_id" | "first_name" | "last_name" | "establishment_id" | "establishment_raison_sociale" | "establishment_siret" | "createdAt" | "email" | "phone" | "type" @@ -206,4 +149,4 @@ const getUserAndRecruitersDataForOpcoUser = async (opco: string): Promise `mna-${randomUUID()}` * @returns {Promise} */ export const getUsers = async (query: FilterQuery, options, { page, limit }) => { - const response = await UserRecruteur.paginate({ query, ...options, page, limit, lean: true, select: "-password" }) + const response = await UserRecruteur.paginate({ query, ...options, page, limit, lean: true }) return { pagination: { page: response?.page, diff --git a/server/tests/integration/common/users.test.ts b/server/tests/integration/common/users.test.ts index 753ff73aa8..c432bb0df5 100644 --- a/server/tests/integration/common/users.test.ts +++ b/server/tests/integration/common/users.test.ts @@ -6,23 +6,21 @@ import { useMongo } from "@tests/utils/mongo.utils" import { User } from "../../../src/common/model/index" import { ROLES } from "../../../src/services/constant.service" -import { authenticate, changePassword, createUser } from "../../../src/services/user.service" +import { createUser } from "../../../src/services/user.service" describe("users", () => { useMongo() it("Permet de créer un utilisateur", async () => { - const created = await createUser("user", "password", {}) + const created = await createUser("user", {}) assert.strictEqual(created.username, "user") - assert.strictEqual(created.password.startsWith(`$6$rounds=${process.env.LBA_AUTH_PASSWORD_HASH_ROUNDS}`), true) const found = await User.findOne({ username: "user" }) assert.strictEqual(found?.username, "user") - assert.strictEqual(found?.password.startsWith(`$6$rounds=${process.env.LBA_AUTH_PASSWORD_HASH_ROUNDS}`), true) }) it("Permet de créer un utilisateur avec le role d'administrateur", async () => { - const user = await createUser("userAdmin", "password", { role: ROLES.administrator }) + const user = await createUser("userAdmin", { role: ROLES.administrator }) const found = await User.findOne({ username: "userAdmin" }) assert.strictEqual(user.role, ROLES.administrator) @@ -30,7 +28,7 @@ describe("users", () => { }) it("Permet de créer un utilisateur avec le role de candidat", async () => { - const user = await createUser("userCandidat", "password", { role: ROLES.candidat }) + const user = await createUser("userCandidat", { role: ROLES.candidat }) const found = await User.findOne({ username: "userCandidat" }) assert.strictEqual(user.role, ROLES.candidat) @@ -38,32 +36,10 @@ describe("users", () => { }) it("Permet de créer un utilisateur avec le role de cfa", async () => { - const user = await createUser("userCfa", "password", { role: ROLES.cfa }) + const user = await createUser("userCfa", { role: ROLES.cfa }) const found = await User.findOne({ username: "userCfa" }) assert.strictEqual(user.role, ROLES.cfa) assert.strictEqual(found?.role, ROLES.cfa) }) - - it("Vérifie que le mot de passe est valide", async () => { - await createUser("user", "password", {}) - const user = await authenticate("user", "password") - - assert.strictEqual(user?.username, "user") - }) - - it("Vérifie que le mot de passe est invalide", async () => { - await createUser("user", "password", {}) - const user = await authenticate("user", "INVALID") - - assert.strictEqual(user, null) - }) - - it("Vérifie qu'on peut changer le mot de passe d'un utilisateur", async () => { - await createUser("user", "password", {}) - await changePassword("user", "newPassword") - const user = await authenticate("user", "newPassword") - - assert.strictEqual(user?.username, "user") - }) })