diff --git a/.classpath b/.classpath index 8eb78c7..dc62fe9 100644 --- a/.classpath +++ b/.classpath @@ -1,6 +1,10 @@ - + + + + + @@ -13,5 +17,8 @@ + + + diff --git a/.gitignore b/.gitignore index c5a661b..38fb1c2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ config.txt dist/ testApi/ .apt_generated/* +/.apt_generated/ diff --git a/angus-activation-2.0.1.jar b/angus-activation-2.0.1.jar new file mode 100644 index 0000000..9d56221 Binary files /dev/null and b/angus-activation-2.0.1.jar differ diff --git a/jakarta.activation-api-2.1.2.jar b/jakarta.activation-api-2.1.2.jar new file mode 100644 index 0000000..ea57b3e Binary files /dev/null and b/jakarta.activation-api-2.1.2.jar differ diff --git a/jakarta.mail-2.0.2.jar b/jakarta.mail-2.0.2.jar new file mode 100644 index 0000000..7192cb2 Binary files /dev/null and b/jakarta.mail-2.0.2.jar differ diff --git a/src/dev/peerat/backend/Configuration.java b/src/dev/peerat/backend/Configuration.java index 41c3bf9..8e05047 100644 --- a/src/dev/peerat/backend/Configuration.java +++ b/src/dev/peerat/backend/Configuration.java @@ -7,6 +7,8 @@ import java.io.FileReader; import java.io.FileWriter; import java.lang.reflect.Field; +import dev.peerat.backend.utils.Mail; + public class Configuration { private String db_host; @@ -29,6 +31,12 @@ public class Configuration { private int groupJoinMinutes; private String groupQuitMinutes; + + private String mailUsername; + private String mailPassword; + private String mailSmtpHost; + private int mailSmptPort; + private String mailFromAddress; private File file; @@ -173,4 +181,13 @@ public class Configuration { public String getGroupQuitMinutes(){ return this.groupQuitMinutes; } + + public Mail getMail(){ + return new Mail( + this.mailUsername, + this.mailPassword, + this.mailSmtpHost, + this.mailSmptPort, + this.mailFromAddress); + } } \ No newline at end of file diff --git a/src/dev/peerat/backend/Main.java b/src/dev/peerat/backend/Main.java index 37f4d46..03e1806 100644 --- a/src/dev/peerat/backend/Main.java +++ b/src/dev/peerat/backend/Main.java @@ -2,11 +2,14 @@ package dev.peerat.backend; import static dev.peerat.framework.RequestType.OPTIONS; +import java.util.HashMap; +import java.util.Map; import java.util.regex.Matcher; import dev.peerat.backend.model.Completion; import dev.peerat.backend.model.Group; import dev.peerat.backend.model.PeerAtUser; +import dev.peerat.backend.model.Player; import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.routes.BadgeDetails; import dev.peerat.backend.routes.ChapterElement; @@ -14,6 +17,7 @@ import dev.peerat.backend.routes.ChapterList; import dev.peerat.backend.routes.DynamicLeaderboard; import dev.peerat.backend.routes.Leaderboard; import dev.peerat.backend.routes.Login; +import dev.peerat.backend.routes.MailConfirmation; import dev.peerat.backend.routes.PlayerDetails; import dev.peerat.backend.routes.PuzzleElement; import dev.peerat.backend.routes.PuzzleResponse; @@ -23,6 +27,7 @@ import dev.peerat.backend.routes.groups.GroupCreate; import dev.peerat.backend.routes.groups.GroupJoin; import dev.peerat.backend.routes.groups.GroupList; import dev.peerat.backend.routes.groups.GroupQuit; +import dev.peerat.backend.utils.Mail; import dev.peerat.framework.Context; import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpWriter; @@ -80,10 +85,12 @@ public class Main{ } private static void initRoutes(Router router, DatabaseRepository repo, Configuration config){ + Map playersWaiting = new HashMap<>(); router.register(new ChapterElement(repo)); router.register(new ChapterList(repo)); router.register(new PuzzleElement(repo)); - router.register(new Register(repo, router, config.getUsersFiles())); + router.register(new Register(repo, router, config.getUsersFiles(), playersWaiting)); + router.register(new MailConfirmation(repo, router, config.getUsersFiles(), playersWaiting)); router.register(new Login(repo, router)); router.register(new Result(repo)); router.register(new Leaderboard(repo)); diff --git a/src/dev/peerat/backend/model/Player.java b/src/dev/peerat/backend/model/Player.java index 1793077..53d5575 100644 --- a/src/dev/peerat/backend/model/Player.java +++ b/src/dev/peerat/backend/model/Player.java @@ -22,12 +22,12 @@ public class Player implements Comparable { private Set badges; - public Player(String pseudo, String email, String firstname, String lastname, String description) { + public Player(String pseudo, String email, String firstname, String lastname) { this.pseudo = pseudo; this.email = email; this.firstname = firstname; this.lastname = lastname; - this.description = description; + this.description = ""; } public Player(String pseudo, int score, int tries) { @@ -36,6 +36,11 @@ public class Player implements Comparable { this.completions.add(new Completion(tries, score)); email = ""; // TO make compareTo and equals works as usual } + + public Player(String email) { + // For player find in Map during register process + this.email = email; + } public String getPseudo() { return this.pseudo; diff --git a/src/dev/peerat/backend/repository/DatabaseRepository.java b/src/dev/peerat/backend/repository/DatabaseRepository.java index 6c51183..259fa88 100644 --- a/src/dev/peerat/backend/repository/DatabaseRepository.java +++ b/src/dev/peerat/backend/repository/DatabaseRepository.java @@ -129,8 +129,7 @@ public class DatabaseRepository { private Player makePlayer(ResultSet playerResult, int id) throws SQLException { Player p = new Player(playerResult.getString("pseudo"), playerResult.getString("email"), - playerResult.getString("firstName"), playerResult.getString("lastName"), - playerResult.getString("description")); + playerResult.getString("firstName"), playerResult.getString("lastName")); if (hasColumn(playerResult, "avatar")) { p.setAvatar(playerResult.getBytes("avatar")); } diff --git a/src/dev/peerat/backend/routes/MailConfirmation.java b/src/dev/peerat/backend/routes/MailConfirmation.java new file mode 100644 index 0000000..62ca4a3 --- /dev/null +++ b/src/dev/peerat/backend/routes/MailConfirmation.java @@ -0,0 +1,96 @@ +package dev.peerat.backend.routes; + +import static dev.peerat.framework.RequestType.POST; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Map; +import java.util.regex.Matcher; + +import org.json.simple.JSONObject; + +import dev.peerat.backend.bonus.extract.RouteDoc; +import dev.peerat.backend.model.PeerAtUser; +import dev.peerat.backend.model.Player; +import dev.peerat.backend.repository.DatabaseRepository; +import dev.peerat.framework.Context; +import dev.peerat.framework.HttpReader; +import dev.peerat.framework.HttpWriter; +import dev.peerat.framework.Response; +import dev.peerat.framework.Route; +import dev.peerat.framework.Router; + +public class MailConfirmation implements Response { + + private DatabaseRepository databaseRepo; + private Router router; + private String usersFilesPath; + private Map playersWaiting; + + public MailConfirmation(DatabaseRepository databaseRepo, Router router, String initUsersFilesPath, + Map playersWaiting) { + this.databaseRepo = databaseRepo; + this.router = router; + usersFilesPath = initUsersFilesPath; + } + + @RouteDoc(path = "/confirmation", responseCode = 200, responseDescription = "L'utilisateur est inscrit") + @RouteDoc(responseCode = 403, responseDescription = "L'utilisateur est connecté") + @RouteDoc(responseCode = 400, responseDescription = "Aucune données fournie / données invalide") + + @Route(path = "^\\/confirmation$", type = POST) + public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception { + if (context.getUser() != null) { + context.response(403); + return; + } + JSONObject informations = reader.readJson(); + if (informations != null) { + boolean allNecessaryFieldsFilled = informations.containsKey("email") && informations.containsKey("code") + && informations.containsKey("passwd"); + if (!allNecessaryFieldsFilled) { + context.response(400); + return; + } + String email = (String) informations.get("email"); + String password = (String) informations.get("passwd"); + int code = (int) informations.get("code"); + + Player newPlayer = getPlayerFromEmail(email); + if (newPlayer != null && code == playersWaiting.get(newPlayer)) { + String pseudo = newPlayer.getPseudo(); + int id; + if ((id = databaseRepo.register(pseudo, email, password, newPlayer.getFirstname(), newPlayer.getLastname(), "", "", "")) >= 0) { + context.response(200, "Access-Control-Expose-Headers: Authorization", + "Authorization: Bearer " + this.router.createAuthUser(new PeerAtUser(id))); + createFolderToSaveSourceCode(pseudo); + return; + } else { + context.response(400); + JSONObject error = new JSONObject(); + error.put("username_valid", pseudo); + error.put("email_valid", email); + writer.write(error.toJSONString()); + return; + } + } + } + context.response(400); + } + + private void createFolderToSaveSourceCode(String pseudo) throws IOException { + + Files.createDirectories(Paths.get(String.format("%s/%s", usersFilesPath, pseudo))); + } + + private Player getPlayerFromEmail(String email) { + Player toMatch = new Player(email); + for (Player p: playersWaiting.keySet()) { + if (p.equals(toMatch)) { + return p; + } + } + return null; + } +} diff --git a/src/dev/peerat/backend/routes/Register.java b/src/dev/peerat/backend/routes/Register.java index f8968e6..782a9a2 100644 --- a/src/dev/peerat/backend/routes/Register.java +++ b/src/dev/peerat/backend/routes/Register.java @@ -5,12 +5,16 @@ import static dev.peerat.framework.RequestType.POST; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; import java.util.regex.Matcher; import org.json.simple.JSONObject; import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.model.PeerAtUser; +import dev.peerat.backend.model.Player; import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.framework.Context; import dev.peerat.framework.HttpReader; @@ -24,69 +28,62 @@ public class Register implements Response { private DatabaseRepository databaseRepo; private Router router; private String usersFilesPath; + private Map playersWaiting; - public Register(DatabaseRepository databaseRepo, Router router, String initUsersFilesPath) { + public Register(DatabaseRepository databaseRepo, Router router, String initUsersFilesPath, + Map playersWaiting) { this.databaseRepo = databaseRepo; this.router = router; usersFilesPath = initUsersFilesPath; } - + @RouteDoc(path = "/register", responseCode = 200, responseDescription = "L'utilisateur est inscrit") @RouteDoc(responseCode = 403, responseDescription = "L'utilisateur est connecté") @RouteDoc(responseCode = 400, responseDescription = "Aucune données fournie / données invalide") @Route(path = "^\\/register$", type = POST) - public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{ - if (context.getUser() != null){ + public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception { + if (context.getUser() != null) { context.response(403); return; } JSONObject informations = reader.readJson(); if (informations != null) { - boolean allFieldsFilled = informations.containsKey("pseudo") && informations.containsKey("email") - && informations.containsKey("passwd") && informations.containsKey("firstname") - && informations.containsKey("lastname") && informations.containsKey("description") - && informations.containsKey("sgroup") && informations.containsKey("avatar"); - if (!allFieldsFilled) { - context.response(403); + boolean allNecessaryFieldsFilled = informations.containsKey("pseudo") && informations.containsKey("email") + && informations.containsKey("firstname") && informations.containsKey("lastname"); + if (!allNecessaryFieldsFilled) { + context.response(400); return; } String pseudo = (String) informations.get("pseudo"); String email = (String) informations.get("email"); - String password = (String) informations.get("passwd"); String firstname = (String) informations.get("firstname"); String lastname = (String) informations.get("lastname"); - String description = (String) informations.get("description"); - String group = (String) informations.get("sgroup"); - String avatar = (String) informations.get("avatar"); - + boolean pseudoAvailable = databaseRepo.checkPseudoAvailability(pseudo); boolean emailAvailable = databaseRepo.checkEmailAvailability(email); if (pseudoAvailable && emailAvailable) { - int id; - if ((id = databaseRepo.register(pseudo, email, password, firstname, lastname, description, group, - avatar)) >= 0) { - context.response(200, - "Access-Control-Expose-Headers: Authorization", - "Authorization: Bearer " + this.router.createAuthUser(new PeerAtUser(id))); - createFolderToSaveSourceCode(pseudo); - return; - } + Player player = new Player(pseudo, email, firstname, lastname); + playersWaiting.put(player, codeGenerator()); + context.response(200); } else { context.response(400); JSONObject error = new JSONObject(); error.put("username_valid", pseudoAvailable); error.put("email_valid", emailAvailable); writer.write(error.toJSONString()); - return; + } + return; } context.response(400); } - private void createFolderToSaveSourceCode(String pseudo) throws IOException { + private int codeGenerator() { + int min = 1000; + int max = 9999; + return new Random().nextInt((max-min)) + min; - Files.createDirectories(Paths.get(String.format("%s/%s", usersFilesPath, pseudo))); } } diff --git a/src/dev/peerat/backend/utils/Mail.java b/src/dev/peerat/backend/utils/Mail.java new file mode 100644 index 0000000..b6e1137 --- /dev/null +++ b/src/dev/peerat/backend/utils/Mail.java @@ -0,0 +1,58 @@ +package dev.peerat.backend.utils; + +import java.util.Date; +import java.util.Properties; + +import jakarta.mail.Authenticator; +import jakarta.mail.Message; +import jakarta.mail.PasswordAuthentication; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; + +public class Mail { + private Session session; + private String fromAddress; + + public Mail(String initUsername, String initPassword, String initSmtpHost, int initSmtpPort, String initFromAddress) { + System.out.println("login on "+initUsername+" into "+initSmtpHost+":"+initSmtpPort); + Properties props = new Properties(); + props.put("mail.smtp.host", initSmtpHost); + props.put("mail.smtp.port", initSmtpPort); + props.put("mail.smtp.auth", "true"); + props.put("mail.smtp.starttls.enable", "true"); + + Authenticator auth = new Authenticator() { + //override the getPasswordAuthentication method + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(initUsername, initPassword); + } + }; + session = Session.getInstance(props, auth); + fromAddress = initFromAddress; + } + + public void send(String toAddress, String subject, String text) { + try + { + MimeMessage msg = new MimeMessage(session); + //set message headers + msg.addHeader("Content-type", "text/HTML; charset=UTF-8"); + msg.addHeader("format", "flowed"); + msg.addHeader("Content-Transfer-Encoding", "8bit"); + + msg.setFrom(new InternetAddress("ping@peerat.dev", "NoReply-JD")); + msg.setReplyTo(InternetAddress.parse("ping@peerat.dev", false)); + msg.setSubject(subject, "UTF-8"); + msg.setText(text, "UTF-8"); + msg.setSentDate(new Date()); + + msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toAddress, false)); + Transport.send(msg); + } + catch (Exception e) { + e.printStackTrace(); + } + } +}