diff --git a/S2/DevWeb/Projet/mysql/init.sql b/S2/DevWeb/Projet/mysql/init.sql index 8a9ffae..4c5cc8f 100644 --- a/S2/DevWeb/Projet/mysql/init.sql +++ b/S2/DevWeb/Projet/mysql/init.sql @@ -44,12 +44,15 @@ CREATE TABLE IF NOT EXISTS player FOREIGN KEY (user_id) REFERENCES `user` (id) ); -CREATE TABLE IF NOT EXISTS recovery_password_token( +-- Table: RecoveryPasswordToken +CREATE TABLE IF NOT EXISTS recovery_password_token +( id INT NOT NULL AUTO_INCREMENT, - email VARCHAR(255) NOT NULL, + user_id INT NOT NULL, token VARCHAR(255) NOT NULL, expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (id) + PRIMARY KEY (id), + FOREIGN KEY (user_id) REFERENCES `user` (id) ); DELIMITER // diff --git a/S2/DevWeb/Projet/src/main/java/uppa/project/dao/GameDAOFactory.java b/S2/DevWeb/Projet/src/main/java/uppa/project/dao/GameDAOFactory.java index 249bc39..51faef7 100644 --- a/S2/DevWeb/Projet/src/main/java/uppa/project/dao/GameDAOFactory.java +++ b/S2/DevWeb/Projet/src/main/java/uppa/project/dao/GameDAOFactory.java @@ -45,6 +45,11 @@ public abstract class GameDAOFactory { */ public abstract DAO getDAOPlayer() throws DAOException; + /** + * @return le DAO pour la classe/table RecoveryPasswordToken + * @throws DAOException en cas de problème + * @see RecoveryPasswordToken + */ public abstract DAO getDAORecoveryPasswordToken() throws DAOException; } diff --git a/S2/DevWeb/Projet/src/main/java/uppa/project/dao/jpa/DAO_JPA_RecoveryPasswordToken.java b/S2/DevWeb/Projet/src/main/java/uppa/project/dao/jpa/DAO_JPA_RecoveryPasswordToken.java index 3667c0b..050184b 100644 --- a/S2/DevWeb/Projet/src/main/java/uppa/project/dao/jpa/DAO_JPA_RecoveryPasswordToken.java +++ b/S2/DevWeb/Projet/src/main/java/uppa/project/dao/jpa/DAO_JPA_RecoveryPasswordToken.java @@ -16,7 +16,7 @@ import uppa.project.pojo.RecoveryPasswordToken; import uppa.project.provider.EntityManagerProvider; /** - * DAO pour les utilisateurs + * DAO pour les tokens de récupération de mot de passe * * @author Kévin Mitresse * @author Lucàs Vabre diff --git a/S2/DevWeb/Projet/src/main/java/uppa/project/pojo/RecoveryPasswordToken.java b/S2/DevWeb/Projet/src/main/java/uppa/project/pojo/RecoveryPasswordToken.java index c759368..d20408a 100644 --- a/S2/DevWeb/Projet/src/main/java/uppa/project/pojo/RecoveryPasswordToken.java +++ b/S2/DevWeb/Projet/src/main/java/uppa/project/pojo/RecoveryPasswordToken.java @@ -5,6 +5,8 @@ import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.persistence.Temporal; import jakarta.persistence.TemporalType; @@ -24,10 +26,13 @@ public class RecoveryPasswordToken { @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; + @Column(name = "token") private String token; - @Column(name = "email") - private String email; + + @ManyToOne + @JoinColumn(name = "user_id", nullable = false) + private User user; @Temporal(TemporalType.TIMESTAMP) @Column(name = "expires_at") @@ -38,24 +43,27 @@ public class RecoveryPasswordToken { /** * Constructeur + * * @param token - * @param email + * @param user */ - public RecoveryPasswordToken(String token, String email) { + public RecoveryPasswordToken(String token, User user) { this.token = token; - this.email = email; + this.user = user; } /** * Constructeur depuis la base de données + * * @param id * @param token - * @param email + * @param user */ - public RecoveryPasswordToken(int id, String token, String email) { + public RecoveryPasswordToken(int id, String token, User user, Date expiresAt) { this.id = id; this.token = token; - this.email = email; + this.user = user; + this.expiresAt = expiresAt; } /** @@ -86,21 +94,21 @@ public class RecoveryPasswordToken { } /** - * Récupère l'email associé au token + * Récupère l'utilisateur associé au token * - * @return l'email associé au token + * @return l'utilisateur associé au token */ - public String getEmail() { - return email; + public User getUser() { + return user; } /** - * Définit l'email associé au token + * Définit l'utilisateur associé au token * - * @param email + * @param user */ - public void setEmail(String email) { - this.email = email; + public void setUser(User user) { + this.user = user; } /** @@ -120,4 +128,23 @@ public class RecoveryPasswordToken { public void setExpiresAt(Date expiresAt) { this.expiresAt = expiresAt; } + + @Override + public String toString() { + return "RecoveryPasswordToken{" + + "id=" + id + + ", token='" + token + '\'' + + ", user=" + user + + ", expiresAt=" + expiresAt + + '}'; + } + + /** + * Récupère la date d'expiration du token + * + * @return la date d'expiration du token + */ + public Date getExpirationDate() { + return expiresAt; + } } diff --git a/S2/DevWeb/Projet/src/main/java/uppa/project/pojo/User.java b/S2/DevWeb/Projet/src/main/java/uppa/project/pojo/User.java index bd2c374..08c6e43 100644 --- a/S2/DevWeb/Projet/src/main/java/uppa/project/pojo/User.java +++ b/S2/DevWeb/Projet/src/main/java/uppa/project/pojo/User.java @@ -6,7 +6,6 @@ package uppa.project.pojo; -import com.google.gson.Gson; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -42,21 +41,30 @@ public class User implements Serializable { @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private BigDecimal id; + @Column(name = "username") private String username; + @Column(name = "email") private String email; + @Column(name = "password") private String password; + @Temporal(TemporalType.DATE) @Column(name = "birth") private Date birth; + @Column(name = "gender") @Enumerated(EnumType.STRING) private Gender gender; + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Set playedGame; + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private Set recoveryPasswordTokens; + /** * Constructeur par défaut */ diff --git a/S2/DevWeb/Projet/src/main/java/uppa/project/servlet/ForgottenPasswordServlet.java b/S2/DevWeb/Projet/src/main/java/uppa/project/servlet/ForgottenPasswordServlet.java index c4fcb92..22ab5b4 100644 --- a/S2/DevWeb/Projet/src/main/java/uppa/project/servlet/ForgottenPasswordServlet.java +++ b/S2/DevWeb/Projet/src/main/java/uppa/project/servlet/ForgottenPasswordServlet.java @@ -31,11 +31,6 @@ public class ForgottenPasswordServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - if (request.getSession().getAttribute("user") != null) { - response.sendRedirect(request.getContextPath() + "/main-menu"); - return; - } - request.getRequestDispatcher("/WEB-INF/views/forgotten-password.jsp").forward(request, response); } @@ -53,18 +48,9 @@ public class ForgottenPasswordServlet extends HttpServlet { response.sendRedirect(request.getContextPath() + "/forgotten-password?error=1"); } else { String token = UUID.randomUUID().toString(); - System.out.println("Token : " + token); - System.out.println("1"); - RecoveryPasswordToken recoveryPasswordToken = new RecoveryPasswordToken(token, user.getEmail()); - Game_JPA_DAO_Factory jpaDaoFactory = new Game_JPA_DAO_Factory(); - try { - System.out.println("2"); - DAO daoJpaRecoveryPasswordToken = jpaDaoFactory.getDAORecoveryPasswordToken(); - System.out.println("3"); - daoJpaRecoveryPasswordToken.create(recoveryPasswordToken); - } catch (DAOException e) { - throw new RuntimeException(e); - } + + RecoveryPasswordToken recoveryPasswordToken = new RecoveryPasswordToken(token, user); + CreateToken(recoveryPasswordToken); sendRecoveryEmail(email, token); response.sendRedirect(request.getContextPath() + "/forgotten-password?success=200"); } @@ -80,9 +66,12 @@ public class ForgottenPasswordServlet extends HttpServlet { public void sendRecoveryEmail(String email, String token) { String host = "smtp.gmail.com"; - String port = "587"; - String username = System.getenv("MAIL_USERNAME"); - String password = System.getenv("MAIL_PASSWORD"); + String port = "587"; + //TODO: Set up environment variables +// String username = System.getenv("MAIL_USERNAME"); +// String password = System.getenv("MAIL_PASSWORD"); + String username = "kmitresse@gmail.com"; + String password = "xwos ujwf cesq ocyt"; Properties props = new Properties(); props.put("mail.smtp.auth", "true"); @@ -105,7 +94,7 @@ public class ForgottenPasswordServlet extends HttpServlet { message.setSubject("Réinitialisation de votre mot de passe"); message.setText("Bonjour,\n\n" + "Vous avez demandé la réinitialisation de votre mot de passe.\n" + - "Pour cela, veuillez cliquer sur le lien suivant : http://localhost:8080/reset-password?token=" + token + "\n\n" + + "Pour cela, veuillez cliquer sur le lien suivant : http://localhost:8088/project_war_exploded/reset-password?token=" + token + "\n\n" + "Cordialement,\n" + "L'équipe CardRush"); // Envoi du message @@ -128,8 +117,16 @@ public class ForgottenPasswordServlet extends HttpServlet { } catch (DAOException e) { throw new RuntimeException(e); } - + } + public static void CreateToken(RecoveryPasswordToken token){ + Game_JPA_DAO_Factory jpaDaoFactory = new Game_JPA_DAO_Factory(); + try { + DAO daoJpaRecoveryPasswordToken = jpaDaoFactory.getDAORecoveryPasswordToken(); + daoJpaRecoveryPasswordToken.create(token); + } catch (DAOException e) { + throw new RuntimeException(e); } + } public void destroy() { } diff --git a/S2/DevWeb/Projet/src/main/java/uppa/project/servlet/ResetPasswordServlet.java b/S2/DevWeb/Projet/src/main/java/uppa/project/servlet/ResetPasswordServlet.java new file mode 100644 index 0000000..d1f25aa --- /dev/null +++ b/S2/DevWeb/Projet/src/main/java/uppa/project/servlet/ResetPasswordServlet.java @@ -0,0 +1,73 @@ +package uppa.project.servlet; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import uppa.project.dao.DAOException; +import uppa.project.dao.jpa.DAO_JPA_RecoveryPasswordToken; +import uppa.project.dao.jpa.DAO_JPA_User; +import uppa.project.pojo.RecoveryPasswordToken; +import uppa.project.pojo.User; + +@WebServlet(name = "resetPasswordServlet", value = "/reset-password") +public class ResetPasswordServlet extends HttpServlet { + public void init() { + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + + RecoveryPasswordToken recoveryPasswordToken = findRecoveryToken(request.getParameter("token")); + if (recoveryPasswordToken == null) { + response.sendRedirect(request.getContextPath() + "/error?code=404"); + return; + } + request.getRequestDispatcher("/WEB-INF/views/reset-password.jsp").forward(request, response); + } + + /** + * Gestion de la réinitialisation de mot de passe + * + * @param request + * @param response + * @throws IOException + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + RecoveryPasswordToken recoveryPasswordToken = findRecoveryToken(request.getParameter("token")); + User user = recoveryPasswordToken.getUser(); + String newPassword = request.getParameter("newPassword"); + String confirmPassword = request.getParameter("confirmPassword"); + System.out.println("newPassword: " + newPassword); + System.out.println("confirmPassword: " + confirmPassword); + System.out.println(!newPassword.equals(confirmPassword)); + if (!newPassword.equals(confirmPassword)) { + System.out.println("ici"); + response.sendRedirect(request.getContextPath() + "/reset-password?error=1&token=" + recoveryPasswordToken.getToken()); + return; + } + user.setPassword(newPassword); + DAO_JPA_User daoJpaUser = null; + try { + daoJpaUser = new DAO_JPA_User(); + daoJpaUser.update(user); + response.sendRedirect(request.getContextPath() + "/login?success=password-modified"); + } catch (DAOException e) { + response.sendRedirect(request.getContextPath() + "/reset-password?error=2"); + } + } + + public static RecoveryPasswordToken findRecoveryToken(String token) { + try { + DAO_JPA_RecoveryPasswordToken daoJpaRecoveryPasswordToken = new DAO_JPA_RecoveryPasswordToken(); + RecoveryPasswordToken[] recoveryPasswordTokens = daoJpaRecoveryPasswordToken.findByField("token",token); + if (recoveryPasswordTokens.length == 0) { + return null; + } + return recoveryPasswordTokens[0]; + } catch (DAOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/S2/DevWeb/Projet/src/main/resources/META-INF/persistence.xml b/S2/DevWeb/Projet/src/main/resources/META-INF/persistence.xml index 5f4edfe..8d3f42d 100644 --- a/S2/DevWeb/Projet/src/main/resources/META-INF/persistence.xml +++ b/S2/DevWeb/Projet/src/main/resources/META-INF/persistence.xml @@ -8,6 +8,7 @@ uppa.project.pojo.User uppa.project.pojo.Game uppa.project.pojo.Player + uppa.project.pojo.RecoveryPasswordToken diff --git a/S2/DevWeb/Projet/src/main/webapp/WEB-INF/static/js/login.js b/S2/DevWeb/Projet/src/main/webapp/WEB-INF/static/js/login.js index 71db118..5fc8001 100644 --- a/S2/DevWeb/Projet/src/main/webapp/WEB-INF/static/js/login.js +++ b/S2/DevWeb/Projet/src/main/webapp/WEB-INF/static/js/login.js @@ -23,3 +23,10 @@ loginForm.addEventListener("submit", (event) => { .catch(error => console.error("Error:", error)) ; }); + +//Récupération de mot de passe réussie = redirection vers la page de connexion + message d'alerte +const urlParams = new URLSearchParams(window.location.search); +const succes = urlParams.get('succes'); +if (succes != null) { + window.alert(succes); +} diff --git a/S2/DevWeb/Projet/src/main/webapp/WEB-INF/static/js/reset-password.js b/S2/DevWeb/Projet/src/main/webapp/WEB-INF/static/js/reset-password.js new file mode 100644 index 0000000..f2434c2 --- /dev/null +++ b/S2/DevWeb/Projet/src/main/webapp/WEB-INF/static/js/reset-password.js @@ -0,0 +1,33 @@ +const ResetPasswordForm = document.getElementById("resetPasswordForm"); + +ResetPasswordForm.addEventListener("submit", function (event) { + event.preventDefault(); + const formData = new FormData(ResetPasswordForm); + const data = {}; + formData.forEach((value, key) => data[key] = value); + + const action = loginForm.getAttribute("action") + const method = loginForm.getAttribute("method") + + + fetch("/reset-password", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(data) + }).then(response => { + if (response.ok) { + window.location.href = "/login"; + } else { + response.json().then(data => { + alert(data.message); + }); + } + }).catch(error => { + console.error("Error:", error); + }); + + +}); + diff --git a/S2/DevWeb/Projet/src/main/webapp/WEB-INF/views/reset-password.jsp b/S2/DevWeb/Projet/src/main/webapp/WEB-INF/views/reset-password.jsp new file mode 100644 index 0000000..b070d20 --- /dev/null +++ b/S2/DevWeb/Projet/src/main/webapp/WEB-INF/views/reset-password.jsp @@ -0,0 +1,54 @@ +<%@ page import="uppa.project.dao.jpa.DAO_JPA_RecoveryPasswordToken" %> +<%@ page import="uppa.project.pojo.RecoveryPasswordToken" %> +<%@ page import="uppa.project.dao.DAOException" %> +<%-- + Created by IntelliJ IDEA. + User: kmitr + Date: 22/03/2024 + Time: 13:48 + To change this template use File | Settings | File Templates. +--%> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + Recovery password + + +
+ <% + DAO_JPA_RecoveryPasswordToken dao = null; + RecoveryPasswordToken[] token; + try { + dao = new DAO_JPA_RecoveryPasswordToken(); + token = dao.findByField("token",request.getParameter("token")); + } catch (DAOException e) { + throw new RuntimeException(e); + } + if (token.length == 0 || token[0] == null || token[0].getExpirationDate()== null) {%> +

Lien invalide

+ <% + } else if (token[0].getExpirationDate().compareTo(new java.util.Date()) >0){ + %> +

Lien expiré

+ <% + } else { + %> + +

Récupération du mot de passe

+
+ + + + + <% if (request.getParameter("error") != null && request.getParameter("error").equals("1")) {%> +

Les mots de passe ne correspondent pas

+ <% } %> + + +
+ <% + } + %> +
+ +