mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
Merge branch 'main' of https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir into feature/add-room-collection
This commit is contained in:
commit
cd13c5f798
16 changed files with 275 additions and 64 deletions
|
|
@ -15,7 +15,7 @@ const OAuthCallback: React.FC = () => {
|
|||
if (user) {
|
||||
apiService.saveToken(user);
|
||||
apiService.saveUsername(username || "");
|
||||
navigate('/');
|
||||
navigate('/teacher/dashboard');
|
||||
} else {
|
||||
navigate('/login');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const Register: React.FC = () => {
|
|||
const [name, setName] = useState(''); // State for name
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [roles, setRoles] = useState<string[]>(['student']); // Set 'student' as the default role
|
||||
const [roles, setRoles] = useState<string[]>(['teacher']); // Set 'student' as the default role
|
||||
|
||||
const [connectionError, setConnectionError] = useState<string>('');
|
||||
const [isConnecting] = useState<boolean>(false);
|
||||
|
|
|
|||
|
|
@ -73,12 +73,85 @@ class ApiService {
|
|||
return false;
|
||||
}
|
||||
|
||||
console.log("ApiService: isLoggedIn: Token:", token);
|
||||
|
||||
// Update token expiry
|
||||
this.saveToken(token);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public isLoggedInTeacher(): boolean {
|
||||
const token = this.getToken();
|
||||
|
||||
|
||||
if (token == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("ApiService: isLoggedInTeacher: Token:", token);
|
||||
const decodedToken = jwtDecode(token) as { roles: string[] };
|
||||
|
||||
/////// REMOVE BELOW
|
||||
// automatically add teacher role if not present
|
||||
if (!decodedToken.roles.includes('teacher')) {
|
||||
decodedToken.roles.push('teacher');
|
||||
}
|
||||
////// REMOVE ABOVE
|
||||
const userRoles = decodedToken.roles;
|
||||
const requiredRole = 'teacher';
|
||||
|
||||
console.log("ApiService: isLoggedInTeacher: UserRoles:", userRoles);
|
||||
if (!userRoles || !userRoles.includes(requiredRole)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update token expiry
|
||||
this.saveToken(token);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error decoding token:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public saveUsername(username: string): void {
|
||||
if (!username || username.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const object = {
|
||||
username: username
|
||||
}
|
||||
|
||||
localStorage.setItem("username", JSON.stringify(object));
|
||||
}
|
||||
|
||||
public getUsername(): string {
|
||||
const objectStr = localStorage.getItem("username");
|
||||
|
||||
if (!objectStr) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const object = JSON.parse(objectStr)
|
||||
|
||||
return object.username;
|
||||
}
|
||||
|
||||
// Route to know if rooms need authentication to join
|
||||
public async getRoomsRequireAuth(): Promise<any> {
|
||||
const url: string = this.constructRequestUrl(`/auth/getRoomsRequireAuth`);
|
||||
const result: AxiosResponse = await axios.get(url);
|
||||
|
||||
if (result.status == 200) {
|
||||
return result.data.roomsRequireAuth;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public logout(): void {
|
||||
return localStorage.removeItem("jwt");
|
||||
}
|
||||
|
|
|
|||
109
docker-compose-local.yaml
Normal file
109
docker-compose-local.yaml
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
version: '3'
|
||||
|
||||
services:
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./client
|
||||
dockerfile: Dockerfile
|
||||
container_name: frontend
|
||||
ports:
|
||||
- "5173:5173"
|
||||
restart: always
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ./server
|
||||
dockerfile: Dockerfile
|
||||
container_name: backend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
PORT: 3000
|
||||
MONGO_URI: "mongodb://mongo:27017/evaluetonsavoir"
|
||||
MONGO_DATABASE: evaluetonsavoir
|
||||
EMAIL_SERVICE: gmail
|
||||
SENDER_EMAIL: infoevaluetonsavoir@gmail.com
|
||||
EMAIL_PSW: 'vvml wmfr dkzb vjzb'
|
||||
JWT_SECRET: haQdgd2jp09qb897GeBZyJetC8ECSpbFJe
|
||||
SESSION_Secret: 'lookMomImQuizzing'
|
||||
SITE_URL: http://localhost
|
||||
FRONTEND_PORT: 5173
|
||||
USE_PORTS: false
|
||||
AUTHENTICATED_ROOMS: false
|
||||
volumes:
|
||||
- ./server/auth_config.json:/usr/src/app/serveur/config/auth_config.json
|
||||
depends_on:
|
||||
- mongo
|
||||
- keycloak
|
||||
restart: always
|
||||
|
||||
# Ce conteneur sert de routeur pour assurer le bon fonctionnement de l'application
|
||||
nginx:
|
||||
image: fuhrmanator/evaluetonsavoir-routeur:latest
|
||||
container_name: nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
- backend
|
||||
- frontend
|
||||
restart: always
|
||||
|
||||
# Ce conteneur est la base de données principale pour l'application
|
||||
mongo:
|
||||
image: mongo
|
||||
container_name: mongo
|
||||
ports:
|
||||
- "27017:27017"
|
||||
tty: true
|
||||
volumes:
|
||||
- mongodb_data:/data/db
|
||||
restart: always
|
||||
|
||||
# Ce conteneur cherche des mises à jour à 5h du matin
|
||||
watchtower:
|
||||
image: containrrr/watchtower
|
||||
container_name: watchtower
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- TZ=America/Montreal
|
||||
- WATCHTOWER_CLEANUP=true
|
||||
- WATCHTOWER_DEBUG=true
|
||||
- WATCHTOWER_INCLUDE_RESTARTING=true
|
||||
- WATCHTOWER_SCHEDULE=0 0 5 * * * # At 5 am everyday
|
||||
restart: always
|
||||
|
||||
watchtower-once:
|
||||
image: containrrr/watchtower
|
||||
container_name: watchtower-once
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: --run-once
|
||||
environment:
|
||||
- TZ=America/Montreal
|
||||
- WATCHTOWER_CLEANUP=true
|
||||
- WATCHTOWER_DEBUG=true
|
||||
- WATCHTOWER_INCLUDE_RESTARTING=true
|
||||
restart: "no"
|
||||
|
||||
keycloak:
|
||||
container_name: keycloak
|
||||
image: quay.io/keycloak/keycloak:latest
|
||||
environment:
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: admin123
|
||||
KC_HEALTH_ENABLED: 'true'
|
||||
KC_FEATURES: preview
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- ./oauth-tester/config.json:/opt/keycloak/data/import/realm-config.json
|
||||
command:
|
||||
- start-dev
|
||||
- --import-realm
|
||||
- --hostname-strict=false
|
||||
|
||||
volumes:
|
||||
mongodb_data:
|
||||
external: false
|
||||
|
|
@ -3,18 +3,19 @@ version: '3'
|
|||
services:
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./client
|
||||
dockerfile: Dockerfile
|
||||
image: fuhrmanator/evaluetonsavoir-frontend:latest
|
||||
container_name: frontend
|
||||
environment:
|
||||
# Define empty VITE_BACKEND_URL because it's production
|
||||
- VITE_BACKEND_URL=
|
||||
# Define empty VITE_BACKEND_SOCKET_URL so it will default to window.location.host
|
||||
- VITE_BACKEND_SOCKET_URL=
|
||||
ports:
|
||||
- "5173:5173"
|
||||
restart: always
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ./server
|
||||
dockerfile: Dockerfile
|
||||
image: fuhrmanator/evaluetonsavoir-backend:latest
|
||||
container_name: backend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
|
@ -28,11 +29,12 @@ services:
|
|||
JWT_SECRET: haQdgd2jp09qb897GeBZyJetC8ECSpbFJe
|
||||
SESSION_Secret: 'lookMomImQuizzing'
|
||||
SITE_URL: http://localhost
|
||||
OIDC_URL: https://evalsa.etsmtl.ca
|
||||
FRONTEND_PORT: 5173
|
||||
USE_PORTS: false
|
||||
AUTHENTICATED_ROOMS: false
|
||||
volumes:
|
||||
- ./server/auth_config.json:/usr/src/app/serveur/config/auth_config.json
|
||||
- /opt/EvalueTonSavoir/auth_config.json:/usr/src/app/serveur/auth_config.json
|
||||
depends_on:
|
||||
- mongo
|
||||
- keycloak
|
||||
|
|
@ -98,7 +100,7 @@ services:
|
|||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- ./oauth-tester/config.json:/opt/keycloak/data/import/realm-config.json
|
||||
- /opt/EvalueTonSavoir/oauth-tester/config.json:/opt/keycloak/data/import/realm-config.json
|
||||
command:
|
||||
- start-dev
|
||||
- --import-realm
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@ app.use(session({
|
|||
cookie: { secure: process.env.NODE_ENV === 'production' }
|
||||
}));
|
||||
|
||||
let authManager = new AuthManager(app,null,userModel);
|
||||
authManager.getUserModel();
|
||||
let _authManager = new AuthManager(app,null,userModel);
|
||||
app.use(errorHandler);
|
||||
|
||||
// Start server
|
||||
|
|
|
|||
|
|
@ -7,13 +7,15 @@ const AppError = require('../middleware/AppError.js');
|
|||
|
||||
class AuthManager{
|
||||
constructor(expressapp,configs=null,userModel){
|
||||
console.log(`AuthManager: constructor: configs: ${JSON.stringify(configs)}`);
|
||||
console.log(`AuthManager: constructor: userModel: ${JSON.stringify(userModel)}`);
|
||||
this.modules = []
|
||||
this.app = expressapp
|
||||
|
||||
this.configs = configs ?? (new AuthConfig()).loadConfig()
|
||||
this.addModules()
|
||||
this.registerAuths()
|
||||
this.simpleregister = userModel;
|
||||
this.registerAuths()
|
||||
}
|
||||
|
||||
getUserModel(){
|
||||
|
|
@ -39,9 +41,10 @@ class AuthManager{
|
|||
}
|
||||
|
||||
async registerAuths(){
|
||||
console.log(``);
|
||||
for(const module of this.modules){
|
||||
try{
|
||||
module.registerAuth(this.app)
|
||||
module.registerAuth(this.app, this.simpleregister);
|
||||
} catch(error){
|
||||
console.error(`L'enregistrement du module ${module} a échoué.`);
|
||||
console.error(`Error: ${error} `);
|
||||
|
|
@ -56,7 +59,16 @@ class AuthManager{
|
|||
console.info(`L'utilisateur '${userInfo.name}' vient de se connecter`)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async loginSimple(email,pswd,req,res,next){ //passport and simpleauth use next
|
||||
const userInfo = await this.simpleregister.login(email, pswd);
|
||||
const tokenToSave = jwt.create(userInfo.email, userInfo._id,userInfo.roles);
|
||||
res.redirect(`/auth/callback?user=${tokenToSave}&username=${userInfo.name}`);
|
||||
console.info(`L'utilisateur '${userInfo.name}' vient de se connecter`)
|
||||
}
|
||||
|
||||
async register(userInfos){
|
||||
console.log(userInfos);
|
||||
if (!userInfos.email || !userInfos.password) {
|
||||
throw new AppError(MISSING_REQUIRED_PARAMETER);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
var OAuth2Strategy = require('passport-oauth2')
|
||||
var authUserAssoc = require('../../../models/authUserAssociation')
|
||||
var users = require('../../../models/users')
|
||||
var { hasNestedValue } = require('../../../utils')
|
||||
|
||||
class PassportOAuth {
|
||||
|
|
@ -9,8 +8,8 @@ class PassportOAuth {
|
|||
this.auth_name = auth_name
|
||||
}
|
||||
|
||||
register(app, passport, endpoint, name, provider) {
|
||||
const cb_url = `${process.env['BACKEND_URL']}${endpoint}/${name}/callback`
|
||||
register(app, passport, endpoint, name, provider, userModel) {
|
||||
const cb_url = `${process.env['OIDC_URL']}${endpoint}/${name}/callback`
|
||||
const self = this
|
||||
const scope = 'openid profile email offline_access' + ` ${provider.OAUTH_ADD_SCOPE}`;
|
||||
|
||||
|
|
@ -43,14 +42,14 @@ class PassportOAuth {
|
|||
|
||||
let user_account
|
||||
if (user_association) {
|
||||
user_account = await users.getById(user_association.user_id)
|
||||
user_account = await userModel.getById(user_association.user_id)
|
||||
}
|
||||
else {
|
||||
let user_id = await users.getId(received_user.email)
|
||||
let user_id = await userModel.getId(received_user.email)
|
||||
if (user_id) {
|
||||
user_account = await users.getById(user_id);
|
||||
user_account = await userModel.getById(user_id);
|
||||
} else {
|
||||
received_user.password = users.generatePassword()
|
||||
received_user.password = userModel.generatePassword()
|
||||
user_account = await self.passportjs.register(received_user)
|
||||
}
|
||||
await authUserAssoc.link(self.auth_name, received_user.auth_id, user_account._id)
|
||||
|
|
@ -58,7 +57,7 @@ class PassportOAuth {
|
|||
|
||||
user_account.name = received_user.name
|
||||
user_account.roles = received_user.roles
|
||||
await users.editUser(user_account)
|
||||
await userModel.editUser(user_account)
|
||||
|
||||
// Store the tokens in the session
|
||||
req.session.oauth2Tokens = {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
var OpenIDConnectStrategy = require('passport-openidconnect');
|
||||
var authUserAssoc = require('../../../models/authUserAssociation');
|
||||
var users = require('../../../models/users');
|
||||
var { hasNestedValue } = require('../../../utils');
|
||||
const { MISSING_OIDC_PARAMETER } = require('../../../constants/errorCodes.js');
|
||||
const AppError = require('../../../middleware/AppError.js');
|
||||
const expressListEndpoints = require('express-list-endpoints');
|
||||
|
||||
class PassportOpenIDConnect {
|
||||
constructor(passportjs, auth_name) {
|
||||
|
|
@ -21,12 +21,21 @@ class PassportOpenIDConnect {
|
|||
}
|
||||
}
|
||||
|
||||
async register(app, passport, endpoint, name, provider) {
|
||||
async register(app, passport, endpoint, name, provider, userModel) {
|
||||
|
||||
const config = await this.getConfigFromConfigURL(name, provider)
|
||||
const cb_url = `${process.env['BACKEND_URL']}${endpoint}/${name}/callback`
|
||||
const self = this
|
||||
const scope = 'openid profile email ' + `${provider.OIDC_ADD_SCOPE}`
|
||||
console.log(`oidc.js: register: endpoint: ${endpoint}`);
|
||||
console.log(`oidc.js: register: name: ${name}`);
|
||||
console.log(`oidc.js: register: provider: ${JSON.stringify(provider)}`);
|
||||
console.log(`oidc.js: register: userModel: ${JSON.stringify(userModel)}`);
|
||||
|
||||
const config = await this.getConfigFromConfigURL(name, provider);
|
||||
const cb_url = `${process.env['OIDC_URL']}${endpoint}/${name}/callback`;
|
||||
const self = this;
|
||||
const scope = 'openid profile email ' + `${provider.OIDC_ADD_SCOPE}`;
|
||||
|
||||
console.log(`oidc.js: register: config: ${JSON.stringify(config)}`);
|
||||
console.log(`oidc.js: register: cb_url: ${cb_url}`);
|
||||
console.log(`oidc.js: register: scope: ${scope}`);
|
||||
|
||||
passport.use(name, new OpenIDConnectStrategy({
|
||||
issuer: config.issuer,
|
||||
|
|
@ -41,38 +50,49 @@ class PassportOpenIDConnect {
|
|||
},
|
||||
// patch pour la librairie permet d'obtenir les groupes, PR en cours mais "morte" : https://github.com/jaredhanson/passport-openidconnect/pull/101
|
||||
async function (req, issuer, profile, times, tok, done) {
|
||||
console.log(`oidc.js: register: issuer: ${JSON.stringify(issuer)}`);
|
||||
console.log(`oidc.js: register: profile: ${JSON.stringify(profile)}`);
|
||||
try {
|
||||
const received_user = {
|
||||
auth_id: profile.id,
|
||||
email: profile.emails[0].value,
|
||||
name: profile.name.givenName,
|
||||
email: profile.emails[0].value.toLowerCase(),
|
||||
name: profile.displayName,
|
||||
roles: []
|
||||
};
|
||||
|
||||
|
||||
if (hasNestedValue(profile, provider.OIDC_ROLE_TEACHER_VALUE)) received_user.roles.push('teacher')
|
||||
if (hasNestedValue(profile, provider.OIDC_ROLE_STUDENT_VALUE)) received_user.roles.push('student')
|
||||
|
||||
const user_association = await authUserAssoc.find_user_association(self.auth_name, received_user.auth_id)
|
||||
console.log(`oidc.js: register: received_user: ${JSON.stringify(received_user)}`);
|
||||
const user_association = await authUserAssoc.find_user_association(self.auth_name, received_user.auth_id);
|
||||
console.log(`oidc.js: register: user_association: ${JSON.stringify(user_association)}`);
|
||||
|
||||
let user_account
|
||||
if (user_association) {
|
||||
user_account = await users.getById(user_association.user_id)
|
||||
console.log(`oidc.js: register: user_association: ${JSON.stringify(user_association)}`);
|
||||
user_account = await userModel.getById(user_association.user_id)
|
||||
console.log(`oidc.js: register: user_account: ${JSON.stringify(user_account)}`);
|
||||
}
|
||||
else {
|
||||
let user_id = await users.getId(received_user.email)
|
||||
console.log(`oidc.js: register: user_association: ${JSON.stringify(user_association)}`);
|
||||
let user_id = await userModel.getId(received_user.email)
|
||||
console.log(`oidc.js: register: user_id: ${JSON.stringify(user_id)}`);
|
||||
if (user_id) {
|
||||
user_account = await users.getById(user_id);
|
||||
user_account = await userModel.getById(user_id);
|
||||
console.log(`oidc.js: register: user_account: ${JSON.stringify(user_account)}`);
|
||||
} else {
|
||||
received_user.password = users.generatePassword()
|
||||
received_user.password = userModel.generatePassword()
|
||||
user_account = await self.passportjs.register(received_user)
|
||||
console.log(`oidc.js: register: user_account: ${JSON.stringify(user_account)}`);
|
||||
}
|
||||
console.log(`oidc.js: register: authUserAssoc.ling.`);
|
||||
await authUserAssoc.link(self.auth_name, received_user.auth_id, user_account._id)
|
||||
}
|
||||
|
||||
user_account.name = received_user.name
|
||||
user_account.roles = received_user.roles
|
||||
await users.editUser(user_account);
|
||||
console.log(`oidc.js: register: calling userModel.editUser: ${JSON.stringify(user_account)}`);
|
||||
await userModel.editUser(user_account);
|
||||
|
||||
return done(null, user_account);
|
||||
} catch (error) {
|
||||
|
|
@ -99,7 +119,8 @@ class PassportOpenIDConnect {
|
|||
}
|
||||
}
|
||||
);
|
||||
console.info(`Ajout de la connexion : ${name}(OIDC)`)
|
||||
console.info(`Ajout de la connexion : ${name}(OIDC)`);
|
||||
console.log(expressListEndpoints(app));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ class PassportJs{
|
|||
this.endpoint = "/api/auth"
|
||||
}
|
||||
|
||||
async registerAuth(expressapp){
|
||||
async registerAuth(expressapp, userModel){
|
||||
console.log(`PassportJs: registerAuth: userModel: ${JSON.stringify(userModel)}`);
|
||||
expressapp.use(passport.initialize());
|
||||
expressapp.use(passport.session());
|
||||
|
||||
|
|
@ -21,7 +22,7 @@ class PassportJs{
|
|||
this.registerProvider(provider.type,auth_id)
|
||||
}
|
||||
try{
|
||||
this.registeredProviders[provider.type].register(expressapp,passport,this.endpoint,name,provider)
|
||||
this.registeredProviders[provider.type].register(expressapp,passport,this.endpoint,name,provider,userModel)
|
||||
authprovider.create(auth_id)
|
||||
} catch(error){
|
||||
console.error(`La connexion ${name} de type ${provider.type} n'as pu être chargé.`);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class SimpleAuth {
|
|||
email: req.body.email,
|
||||
password: req.body.password,
|
||||
roles: req.body.roles
|
||||
}
|
||||
};
|
||||
let user = await self.authmanager.register(userInfos)
|
||||
if (user) res.redirect("/login")
|
||||
}
|
||||
|
|
@ -53,10 +53,7 @@ class SimpleAuth {
|
|||
throw error;
|
||||
}
|
||||
|
||||
const userModel = self.authmanager.getUserModel();
|
||||
const user = userModel.login(email, password);
|
||||
|
||||
await self.authmanager.login(user, req, res, next);
|
||||
await self.authmanager.loginSimple(email, password, req, res, next);
|
||||
} catch (error) {
|
||||
const statusCode = error.statusCode || 500;
|
||||
const message = error.message || "An internal server error occurred";
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"simple-login": {
|
||||
"simpleauth": {
|
||||
"enabled": true,
|
||||
"name": "provider3",
|
||||
"SESSION_SECRET": "your_session_secret"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const AppError = require("./AppError");
|
||||
const fs = require('fs');
|
||||
|
||||
const errorHandler = (error, req, res, _next) => {
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
|
|
|
|||
|
|
@ -53,20 +53,6 @@ class Users {
|
|||
return user;
|
||||
}
|
||||
|
||||
async login(userid) {
|
||||
await this.db.connect();
|
||||
const conn = this.db.getConnection();
|
||||
|
||||
const userCollection = conn.collection("users");
|
||||
const user = await userCollection.findOne({ _id: userid });
|
||||
|
||||
if (!user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
/*
|
||||
async login(email, password) {
|
||||
try {
|
||||
await this.db.connect();
|
||||
|
|
@ -95,7 +81,7 @@ class Users {
|
|||
throw error;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
async resetPassword(email) {
|
||||
const newPassword = this.generatePassword();
|
||||
|
||||
|
|
|
|||
10
server/package-lock.json
generated
10
server/package-lock.json
generated
|
|
@ -14,6 +14,7 @@
|
|||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.4",
|
||||
"express": "^4.18.2",
|
||||
"express-list-endpoints": "^7.1.1",
|
||||
"express-session": "^1.18.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mongodb": "^6.3.0",
|
||||
|
|
@ -3247,6 +3248,15 @@
|
|||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express-list-endpoints": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/express-list-endpoints/-/express-list-endpoints-7.1.1.tgz",
|
||||
"integrity": "sha512-SA6YHH1r6DrioJ4fFJNqiwu1FweGFqJZO9KBApMzwPosoSGPOX2AW0wiMepOXjojjEXDuP9whIvckomheErbJA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/express-session": {
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.4",
|
||||
"express": "^4.18.2",
|
||||
"express-list-endpoints": "^7.1.1",
|
||||
"express-session": "^1.18.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mongodb": "^6.3.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue