Skip to content

Commit

Permalink
feat: remove password (#860)
Browse files Browse the repository at this point in the history
* feat: remove password

* fix: type

* chore: fix preview

* chore: fix preview deployment

---------

Co-authored-by: Moroine Bentefrit <[email protected]>
  • Loading branch information
kevbarns and moroine authored Nov 27, 2023
1 parent e4c0631 commit 63c0b09
Show file tree
Hide file tree
Showing 9 changed files with 31 additions and 98 deletions.
2 changes: 1 addition & 1 deletion .infra/ansible/preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 0 additions & 5 deletions server/src/common/model/schema/user/user.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ export const userSchema = new Schema<IUser>(
description: "Le nom de l'utilisateur",
unique: true,
},
password: {
type: String,
default: null,
description: "Le mot de passe hashé",
},
firstname: {
type: String,
default: null,
Expand Down
1 change: 0 additions & 1 deletion server/src/common/model/schema/user/user.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { ObjectId } from "mongodb"
export interface IUser {
_id: ObjectId
username: string
password: string
firstname: string
lastname: string
phone: string
Expand Down
18 changes: 18 additions & 0 deletions server/src/db/migrations/20231127120528-remove-password.ts
Original file line number Diff line number Diff line change
@@ -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")
}
2 changes: 1 addition & 1 deletion server/src/http/routes/appointmentRequest.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
61 changes: 2 additions & 59 deletions server/src/services/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<IUser>}
*/
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<null|User>}
*/
const authenticate = async (username: string, password: string): Promise<IUser | null> => {
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.
Expand Down Expand Up @@ -79,13 +41,11 @@ const update = (id: string, params) => User.findOneAndUpdate({ _id: id }, params
* @param {User} options
* @returns {Promise<User>}
*/
const createUser = async (username, password, options: Partial<IUser & { hash: string }>) => {
const hash = options.hash || sha512Utils.hash(password)
const createUser = async (username, options: Partial<IUser>) => {
const { firstname, lastname, phone, email, role, type } = options

const user = new User({
username,
password: hash,
firstname,
lastname,
phone,
Expand All @@ -111,23 +71,6 @@ const find = (conditions: FilterQuery<IUser>) => User.find(conditions)
*/
const findOne = (conditions: FilterQuery<IUser>) => User.findOne(conditions)

/**
* @description Updates user's password.
* @param {string} username
* @param {string} newPassword
* @returns {Promise<IUser>}
*/
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"
Expand Down Expand Up @@ -206,4 +149,4 @@ const getUserAndRecruitersDataForOpcoUser = async (opco: string): Promise<TRetur
return results
}

export { authenticate, changePassword, createUser, find, findOne, getUser, getUserAndRecruitersDataForOpcoUser, getUserById, getUserByMail, rehashPassword, update }
export { createUser, find, findOne, getUser, getUserAndRecruitersDataForOpcoUser, getUserById, getUserByMail, update }
4 changes: 2 additions & 2 deletions server/src/services/userRecruteur.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { UserRecruteur } from "../common/model/index"
import config from "../config"

import { createAuthMagicLink } from "./appLinks.service"
import { CFA, ENTREPRISE, VALIDATION_UTILISATEUR, ADMIN } from "./constant.service"
import { ADMIN, CFA, ENTREPRISE, VALIDATION_UTILISATEUR } from "./constant.service"
import mailer from "./mailer.service"

/**
Expand All @@ -30,7 +30,7 @@ export const createApiKey = (): string => `mna-${randomUUID()}`
* @returns {Promise<IUserRecruteur>}
*/
export const getUsers = async (query: FilterQuery<IUserRecruteur>, 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,
Expand Down
34 changes: 5 additions & 29 deletions server/tests/integration/common/users.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,64 +6,40 @@ 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)
assert.strictEqual(found?.role, ROLES.administrator)
})

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)
assert.strictEqual(found?.role, ROLES.candidat)
})

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")
})
})

0 comments on commit 63c0b09

Please sign in to comment.