From 50807f5dfe00c7e5664e11267f9485cf1e9ff385 Mon Sep 17 00:00:00 2001 From: Hoang Anh Mai Date: Sun, 2 May 2021 16:31:43 +0200 Subject: [PATCH 1/5] encoding error --- .gitignore | 4 + README.md | 12 +- data/config.properties | 5 + data/messages.utf8 | 12 ++ data/victims.utf8 | 87 ++++++++++ pom.xml | 29 ++++ src/main/java/Spammer.java | 46 ++++++ .../java/config/ConfigurationManager.java | 32 ++++ src/main/java/config/MessageList.java | 73 +++++++++ src/main/java/config/ServerProperties.java | 64 ++++++++ src/main/java/config/VictimList.java | 40 +++++ src/main/java/model/exception/EmptyList.java | 11 ++ .../exception/GroupMinimumSizeException.java | 12 ++ .../model/exception/IncorrectFormatEmail.java | 11 ++ .../java/model/exception/NoGroupCreated.java | 12 ++ .../java/model/exception/SmtpException.java | 12 ++ src/main/java/model/mail/Group.java | 46 ++++++ src/main/java/model/mail/Message.java | 53 ++++++ src/main/java/model/mail/Person.java | 24 +++ src/main/java/model/prank/Prank.java | 57 +++++++ src/main/java/model/prank/PrankGenerator.java | 151 ++++++++++++++++++ src/main/java/smtp/SmtpClient.java | 94 +++++++++++ src/main/java/utils/Utils.java | 16 ++ 23 files changed, 897 insertions(+), 6 deletions(-) create mode 100644 data/config.properties create mode 100644 data/messages.utf8 create mode 100644 data/victims.utf8 create mode 100644 pom.xml create mode 100644 src/main/java/Spammer.java create mode 100644 src/main/java/config/ConfigurationManager.java create mode 100644 src/main/java/config/MessageList.java create mode 100644 src/main/java/config/ServerProperties.java create mode 100644 src/main/java/config/VictimList.java create mode 100644 src/main/java/model/exception/EmptyList.java create mode 100644 src/main/java/model/exception/GroupMinimumSizeException.java create mode 100644 src/main/java/model/exception/IncorrectFormatEmail.java create mode 100644 src/main/java/model/exception/NoGroupCreated.java create mode 100644 src/main/java/model/exception/SmtpException.java create mode 100644 src/main/java/model/mail/Group.java create mode 100644 src/main/java/model/mail/Message.java create mode 100644 src/main/java/model/mail/Person.java create mode 100644 src/main/java/model/prank/Prank.java create mode 100644 src/main/java/model/prank/PrankGenerator.java create mode 100644 src/main/java/smtp/SmtpClient.java create mode 100644 src/main/java/utils/Utils.java diff --git a/.gitignore b/.gitignore index 0e13eeb..74a1aa5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ buildNumber.properties .mvn/timing.properties # https://github.com/takari/maven-wrapper#usage-without-binary-jar .mvn/wrapper/maven-wrapper.jar +.idea/ +out/ +src/test/ +Teaching-HEIGVD-RES-2021-Labo-SMTP.iml \ No newline at end of file diff --git a/README.md b/README.md index ca01cfd..b5221f0 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ In this lab, you will develop a client application (TCP) in Java. This client application will use the Socket API to communicate with an SMTP server. The code that you write will include a **partial implementation of the SMTP protocol**. These are the objectives of the lab: -* Make practical experiments to become familiar with the **SMTP protocol**. After the lab, you should be able to use a command line tool to **communicate with an SMTP server**. You should be able to send well-formed messages to the server, in order to send emails to the address of your choice. +* Make practical experiments to become familiar with the **SMTP protocol**. After the lab, you should be able to use a command line tool to **communicate with an SMTP server**. You should be able to send well-formed messages to the server, in order to send people to the address of your choice. * Understand the notions of **test double** and **mock server**, which are useful when developing and testing a client-server application. During the lab, you will setup and use such a **mock server**. -* Understand what it means to **implement the SMTP protocol** and be able to send e-mail messages, by working directly on top of the Socket API (i.e. you are not allowed to use a SMTP library). +* Understand what it means to **implement the SMTP protocol** and be able to send e-model.mail messages, by working directly on top of the Socket API (i.e. you are not allowed to use a SMTP library). * **See how easy it is to send forged e-mails**, which appear to be sent by certain people but in reality are issued by malicious users. @@ -19,9 +19,9 @@ In this lab, you will develop a client application (TCP) in Java. This client ap Your mission is to develop a client application that automatically plays pranks on a list of victims: -* The user should be able to **define a list of victims** (concretely, you should be able to create a file containing a list of e-mail addresses). -* The user should be able to **define how many groups of victims should be formed** in a given campaign. In every group of victims, there should be 1 sender and at least 2 recipients (i.e. the minimum size for a group is 3). -* The user should be able to **define a list of e-mail messages**. When a prank is played on a group of victims, then one of these messages should be selected. **The mail should be sent to all group recipients, from the address of the group sender**. In other words, the recipient victims should be lead to believe that the sender victim has sent them. +* The user should be able to **define a list of victims** (concretely, you should be able to create a file containing a list of e-model.mail addresses). +* The user should be able to **define how many groups of victims should be formed** in a given campaign. In every model.mail of victims, there should be 1 sender and at least 2 recipients (i.e. the minimum size for a model.mail is 3). +* The user should be able to **define a list of e-model.mail messages**. When a prank is played on a model.mail of victims, then one of these messages should be selected. **The model.mail should be sent to all model.mail recipients, from the address of the model.mail sender**. In other words, the recipient victims should be lead to believe that the sender victim has sent them. ## Constraints @@ -31,7 +31,7 @@ Your mission is to develop a client application that automatically plays pranks ## Example -Consider that your program generates a group G1. The group sender is Bob. The group recipients are Alice, Claire and Peter. When the prank is played on group G1, then your program should pick one of the fake messages. It should communicate with an SMTP server, so that Alice, Claire and Peter receive an e-mail, which appears to be sent by Bob. +Consider that your program generates a model.mail G1. The model.mail sender is Bob. The model.mail recipients are Alice, Claire and Peter. When the prank is played on model.mail G1, then your program should pick one of the fake messages. It should communicate with an SMTP server, so that Alice, Claire and Peter receive an e-model.mail, which appears to be sent by Bob. ## Teams diff --git a/data/config.properties b/data/config.properties new file mode 100644 index 0000000..ce53f21 --- /dev/null +++ b/data/config.properties @@ -0,0 +1,5 @@ +smtpServerAddress=localhost +smtpServerPort=25 +numberOfGroups=8 +chosenGroupsForPrank=1,3,8 +witnessesToCC=abd@def.com diff --git a/data/messages.utf8 b/data/messages.utf8 new file mode 100644 index 0000000..3406063 --- /dev/null +++ b/data/messages.utf8 @@ -0,0 +1,12 @@ +Subject: Parler derrière mon dos +Ca va? T'as bien parlé derrière mon dos? Et à part ça, on parle de confiance! +Je pensais vraiment pas que t'étais comme ça! Tu t'es bien foutu de moi! +Pourquoi t'es allé raconter à tout le monde que le Père Noël n'existait pas? +========== +Subject: Recherche cerveau +Message important : Votre mobile est en train de mettre à jour votre cerveau... +Recherche cerveau en cours...recherche...recherche...procédure échouée...aucun cerveau trouvé ! +========== +Subject: Journée mondiale de la grippe aviaire +Aujourd'hui, c'est la journée mondiale de la lutte contre la grippe aviaire. +Envoi ce message de solidarité à un dindon ou une pintade que tu connais...voilà, moi de mon côté c'est fait... diff --git a/data/victims.utf8 b/data/victims.utf8 new file mode 100644 index 0000000..37a498d --- /dev/null +++ b/data/victims.utf8 @@ -0,0 +1,87 @@ +ante.bibendum@nostraper.co.uk +lacus.pede@nonduinec.edu +dolor.Quisque.tincidunt@variusorciin.com +nascetur.ridiculus@ultriciesadipiscing.org +eu.dolor@duiFusce.edu +congue@quamCurabitur.ca +vitae.erat.Vivamus@Curabiturvel.ca +at.augue@auctor.co.uk +arcu.Nunc.mauris@ametultricies.net +ullamcorper.Duis.cursus@posuereenim.net +rutrum.magna@Curabituregestas.com +egestas@placeratorcilacus.edu +amet@urnaUt.ca +auctor@semmagna.com +sit.amet@odiosagittis.co.uk +non@Crasvehiculaaliquet.net +tincidunt@nequeIn.edu +massa.Vestibulum.accumsan@semperrutrumFusce.co.uk +mus.Proin.vel@loremeumetus.com +lacus.Cras@dui.net +ac@sodalespurusin.edu +Sed.nulla@adipiscingfringillaporttitor.net +orci.luctus@fringillaornareplacerat.com +Curabitur@eunulla.net +vulputate.risus@nonhendrerit.net +Morbi.metus.Vivamus@NullaaliquetProin.net +feugiat.nec@metusIn.net +risus.varius.orci@Aliquam.net +dolor.Quisque@Mauris.edu +elit@suscipit.com +et.eros.Proin@aliquetProinvelit.ca +sapien.cursus@Phasellusornare.net +facilisis.eget.ipsum@vehiculaet.edu +Donec.tincidunt.Donec@orcilacusvestibulum.edu +Mauris.ut@liberoProin.co.uk +luctus.aliquet@velest.edu +non.enim.Mauris@Aliquam.ca +vulputate.risus@fringilla.co.uk +dictum@ullamcorper.co.uk +Lorem@aaliquetvel.edu +Nunc.mauris@infaucibusorci.org +libero.nec@elit.ca +pede@tempus.net +Phasellus@turpisegestasAliquam.org +id@nibh.org +Quisque.fringilla@anteNuncmauris.net +tellus.justo.sit@Loremipsum.ca +ornare@volutpatornarefacilisis.co.uk +justo.eu@dolorDonec.edu +tempus.non.lacinia@adipiscingfringillaporttitor.net +eget@urnajustofaucibus.org +nunc.sit.amet@odio.net +Donec.egestas.Duis@etmagnisdis.net +euismod.enim.Etiam@nullaat.com +magnis@fringillapurusmauris.edu +gravida@Pellentesqueultricies.net +ante.dictum.mi@nullaIn.edu +malesuada.vel@Suspendisse.edu +tincidunt@convallis.com +fermentum.vel.mauris@ipsumcursusvestibulum.ca +auctor@egetodio.org +non@Nuncpulvinar.net +Nunc.commodo.auctor@ipsumprimis.co.uk +sit.amet@augueeutempor.co.uk +leo@augueeutempor.org +lectus.sit.amet@scelerisque.ca +nibh.lacinia@auctor.ca +metus.urna@tempor.net +eros.nec.tellus@neque.com +vel.est.tempor@ametconsectetuer.com +aliquet@feugiatnec.org +vel@sitametluctus.ca +faucibus@aliquetlibero.ca +Phasellus.elit@enim.ca +non.egestas@ipsum.edu +Vivamus.molestie@turpis.co.uk +eget@asollicitudin.net +et.magnis.dis@dolorelitpellentesque.edu +primis.in@dictum.co.uk +nulla.ante.iaculis@semsempererat.co.uk +fames.ac@Utsemperpretium.ca +elementum.sem@imperdieterat.org +Quisque@eratvolutpatNulla.net +ante.Vivamus@Etiamligula.edu +magnis@commodoipsum.com +orci.lobortis.augue@luctus.com +tortor.Nunc.commodo@est.ca \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..11b5e60 --- /dev/null +++ b/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + org.example + Teaching-HEIGVD-RES-2021-Labo-SMTP + 1.0-SNAPSHOT + + + org.junit.jupiter + junit-jupiter-api + 5.8.0-M1 + test + + + commons-io + commons-io + 2.6 + + + + + 15 + 15 + + + \ No newline at end of file diff --git a/src/main/java/Spammer.java b/src/main/java/Spammer.java new file mode 100644 index 0000000..dfad6bc --- /dev/null +++ b/src/main/java/Spammer.java @@ -0,0 +1,46 @@ +import config.ConfigurationManager; +import config.ServerProperties; +import model.exception.*; +import model.mail.Person; +import model.prank.Prank; +import model.prank.PrankGenerator; +import smtp.SmtpClient; + +import java.io.IOException; +import java.util.ArrayList; + +public class Spammer { + + public static void main(String... args) throws EmptyList, IOException, IncorrectFormatEmail, GroupMinimumSizeException, SmtpException, NoGroupCreated { + ConfigurationManager config = new ConfigurationManager(); + PrankGenerator pg = new PrankGenerator(config); + + pg.generateGroups(); + ArrayList pranks = pg.generatePranks(); + + ServerProperties server = config.getServerProperties(); + String address = server.getServerAddress(); + int port = server.getServerPort(); + int nbGroups = server.getNbVictimGroups(); + + SmtpClient smtp = new SmtpClient(address, port); + + if(server.getChosenGroups()[0] == 0) { + System.out.println("not"); + for(Prank p : pranks) { + smtp.sendMessage(p.getMessage()); + } + } else { + System.out.println("inhere"); + int[] groups = server.getChosenGroups(); + for(int i = 0; i < groups.length; i++) { + int groupId = groups[i] - 1; + if(groupId < nbGroups) { + smtp.sendMessage(pranks.get(groupId).getMessage()); + } else { + throw new IndexOutOfBoundsException("GroupId exceeds the number of groups"); + } + } + } + } +} diff --git a/src/main/java/config/ConfigurationManager.java b/src/main/java/config/ConfigurationManager.java new file mode 100644 index 0000000..35b236f --- /dev/null +++ b/src/main/java/config/ConfigurationManager.java @@ -0,0 +1,32 @@ +package config; + +import model.exception.EmptyList; +import model.exception.IncorrectFormatEmail; + +import java.io.IOException; + +public class ConfigurationManager { + private ServerProperties serverProperties; + private MessageList messageList; + private VictimList victimList; + + public ConfigurationManager() throws EmptyList, IOException, IncorrectFormatEmail { + serverProperties = new ServerProperties("data/config.properties"); + serverProperties.loadFromFile(); + + messageList = new MessageList("data/messages.utf8"); + victimList = new VictimList("data/victims.utf8"); + } + + public ServerProperties getServerProperties() { + return serverProperties; + } + + public MessageList getMessageList() { + return messageList; + } + + public VictimList getVictimList() { + return victimList; + } +} diff --git a/src/main/java/config/MessageList.java b/src/main/java/config/MessageList.java new file mode 100644 index 0000000..aec264c --- /dev/null +++ b/src/main/java/config/MessageList.java @@ -0,0 +1,73 @@ +package config; + +import model.exception.EmptyList; +import model.mail.Message; +import utils.Utils; + +import java.io.*; +import java.nio.charset.StandardCharsets; + +public class MessageList { + private final static String END_OF_MESSAGE = "==========="; + private final static String MESSAGE_SUBJECT = "Subject"; + + private Message[] messages; + private int nbMessages; + + public MessageList(String filename) throws IOException, EmptyList { + + BufferedReader reader = new BufferedReader( + new InputStreamReader(new FileInputStream(filename), StandardCharsets.UTF_8)); + + addEachMessageToList(reader); + } + + public Message[] getMessages() { + return messages; + } + + public int getNbMessages() { + return nbMessages; + } + + public Message getRandomMessage() { + int randomIndex = Utils.randInt(messages.length); + return messages[randomIndex]; + } + + private void addEachMessageToList(BufferedReader reader) throws IOException, EmptyList { + StringBuilder allMessages = new StringBuilder(); + String message; + while((message = reader.readLine()) != null) { + allMessages.append(message).append("\r\n"); + } + + if(allMessages.length() == 0) { + throw new EmptyList("There is no message in the file"); + } + + String[] splitedMessages = allMessages.toString().split("(==========)"); + nbMessages = splitedMessages.length; + + StringBuilder[] splitedMessagesBuilder = new StringBuilder[nbMessages]; + splitedMessagesBuilder[0] = new StringBuilder(splitedMessages[0]); + for(int i = 1; i < nbMessages; i++) { + splitedMessagesBuilder[i] = new StringBuilder(splitedMessages[i]); + splitedMessagesBuilder[i].deleteCharAt(0); + splitedMessagesBuilder[i].deleteCharAt(0); + } + + messages = new Message[nbMessages]; + + for(int i = 0; i < nbMessages; i++) { + messages[i] = new Message(); + String[] content = splitedMessagesBuilder[i].toString().split("\r\n", 2); + + String subject = (content[0].split(".*: "))[1]; + String body = content[1]; + + messages[i].setSubject(subject); + messages[i].setBody(body); + } + } +} diff --git a/src/main/java/config/ServerProperties.java b/src/main/java/config/ServerProperties.java new file mode 100644 index 0000000..4322b2e --- /dev/null +++ b/src/main/java/config/ServerProperties.java @@ -0,0 +1,64 @@ +package config; + +import model.exception.IncorrectFormatEmail; +import model.mail.Person; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.InputMismatchException; +import java.util.Properties; + +public class ServerProperties { + private String filename; + + private String serverAddress; + private int serverPort; + private int nbVictimGroups; + private String[] emailCCs; + + private int[] chosenGroups; + + public ServerProperties(String filename) { + this.filename = filename; + } + + public void loadFromFile() throws IOException { + FileInputStream input = new FileInputStream(filename); + Properties serverConfig = new Properties(); + serverConfig.load(input); + + serverAddress = serverConfig.getProperty("smtpServerAddress"); + serverPort = Integer.parseInt(serverConfig.getProperty("smtpServerPort")); + nbVictimGroups = Integer.parseInt(serverConfig.getProperty("numberOfGroups")); + emailCCs = serverConfig.getProperty("witnessesToCC").split(","); + + String[] groupsInString = serverConfig.getProperty("chosenGroupsForPrank").split(","); + + chosenGroups = new int[groupsInString.length]; + for(int i = 0; i < chosenGroups.length; i++) { + chosenGroups[i] = Integer.parseInt(groupsInString[i]); + } + } + + public String getServerAddress() { + return serverAddress; + } + + public int getServerPort() { + return serverPort; + } + + public int getNbVictimGroups() { + return nbVictimGroups; + } + + public String[] getEmailCCs() { + return emailCCs; + } + + public int[] getChosenGroups() { + return chosenGroups; + } + +} diff --git a/src/main/java/config/VictimList.java b/src/main/java/config/VictimList.java new file mode 100644 index 0000000..fe66262 --- /dev/null +++ b/src/main/java/config/VictimList.java @@ -0,0 +1,40 @@ +package config; + +import model.exception.EmptyList; +import model.exception.IncorrectFormatEmail; +import model.mail.Person; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class VictimList { + private ArrayList people; + private int sizeList; + + public VictimList(String filename) throws IOException, IncorrectFormatEmail, EmptyList { + people = new ArrayList<>(); + + BufferedReader reader = new BufferedReader( + new InputStreamReader(new FileInputStream(filename), StandardCharsets.UTF_8)); + + String email; + while((email = reader.readLine()) != null) { + people.add(new Person(email)); + } + + if(people.isEmpty()) { + throw new EmptyList("There is no email in the file"); + } + + sizeList = people.size(); + } + + public ArrayList getList() { + return people; + } + + public int getSize() { + return sizeList; + } +} diff --git a/src/main/java/model/exception/EmptyList.java b/src/main/java/model/exception/EmptyList.java new file mode 100644 index 0000000..d6d8a9d --- /dev/null +++ b/src/main/java/model/exception/EmptyList.java @@ -0,0 +1,11 @@ +package model.exception; + +public class EmptyList extends Exception { + public EmptyList() { + + } + + public EmptyList(String message) { + + } +} diff --git a/src/main/java/model/exception/GroupMinimumSizeException.java b/src/main/java/model/exception/GroupMinimumSizeException.java new file mode 100644 index 0000000..36a7db1 --- /dev/null +++ b/src/main/java/model/exception/GroupMinimumSizeException.java @@ -0,0 +1,12 @@ +package model.exception; + +public class GroupMinimumSizeException extends Exception { + + public GroupMinimumSizeException() { + super(); + } + + public GroupMinimumSizeException(String message) { + super(message); + } +} diff --git a/src/main/java/model/exception/IncorrectFormatEmail.java b/src/main/java/model/exception/IncorrectFormatEmail.java new file mode 100644 index 0000000..1eda7af --- /dev/null +++ b/src/main/java/model/exception/IncorrectFormatEmail.java @@ -0,0 +1,11 @@ +package model.exception; + +public class IncorrectFormatEmail extends Exception { + public IncorrectFormatEmail() { + super(); + } + + public IncorrectFormatEmail(String message) { + super(message); + } +} diff --git a/src/main/java/model/exception/NoGroupCreated.java b/src/main/java/model/exception/NoGroupCreated.java new file mode 100644 index 0000000..9ed400f --- /dev/null +++ b/src/main/java/model/exception/NoGroupCreated.java @@ -0,0 +1,12 @@ +package model.exception; + +public class NoGroupCreated extends Exception { + + public NoGroupCreated() { + super(); + } + + public NoGroupCreated(String message) { + super(message); + } +} diff --git a/src/main/java/model/exception/SmtpException.java b/src/main/java/model/exception/SmtpException.java new file mode 100644 index 0000000..bca4284 --- /dev/null +++ b/src/main/java/model/exception/SmtpException.java @@ -0,0 +1,12 @@ +package model.exception; + +public class SmtpException extends Exception { + + public SmtpException() { + super(); + } + + public SmtpException(String message) { + super(message); + } +} diff --git a/src/main/java/model/mail/Group.java b/src/main/java/model/mail/Group.java new file mode 100644 index 0000000..1c89c63 --- /dev/null +++ b/src/main/java/model/mail/Group.java @@ -0,0 +1,46 @@ +package model.mail; + +import java.util.ArrayList; + +public class Group { + private static int nbGroups = 0; + + private int id; + private ArrayList members; + + public Group() { + id = ++nbGroups; + members = new ArrayList<>(); + } + + public int getId() { + return id; + } + + public ArrayList getMembers() { + return members; + } + + public Person getMember(int index) { + return members.get(index); + } + + public void addMember(Person person) { + members.add(person); + } + + public int size() { + return members.size(); + } + + @Override + public String toString() { + String res = "Group " + id + "\r\n"; + res += "Members :" + "\r\n"; + for(Person p : members) { + res += p + "\r\n"; + } + + return res; + } +} diff --git a/src/main/java/model/mail/Message.java b/src/main/java/model/mail/Message.java new file mode 100644 index 0000000..4da45a6 --- /dev/null +++ b/src/main/java/model/mail/Message.java @@ -0,0 +1,53 @@ +package model.mail; + +import java.util.ArrayList; + +public class Message { + private String from; + private ArrayList to; + + private ArrayList cc = null; + + private String subject; + private String body; + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public ArrayList getTo() { + return to; + } + + public void setTo(ArrayList to) { + this.to = to; + } + + public ArrayList getCc() { + return cc; + } + + public void setCc(ArrayList cc) { + this.cc = cc; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } +} diff --git a/src/main/java/model/mail/Person.java b/src/main/java/model/mail/Person.java new file mode 100644 index 0000000..8172391 --- /dev/null +++ b/src/main/java/model/mail/Person.java @@ -0,0 +1,24 @@ +package model.mail; + +import model.exception.IncorrectFormatEmail; + +public class Person { + private String email; + + public Person(String email) throws IncorrectFormatEmail { + if(!correctFormatEmail(email)) { + throw new IncorrectFormatEmail(email + " does not have a standard email format"); + } + + this.email = email; + } + + public String getEmail() { + return email; + } + + private boolean correctFormatEmail(String email) { + return email.matches("^[\\w!#$%&’*+/=?`{|}~^-]+(?:\\.[\\w!#$%&’*+/=?`{|}~^-]+)*" + + "@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$"); + } +} diff --git a/src/main/java/model/prank/Prank.java b/src/main/java/model/prank/Prank.java new file mode 100644 index 0000000..a6f9cf8 --- /dev/null +++ b/src/main/java/model/prank/Prank.java @@ -0,0 +1,57 @@ +package model.prank; + +import model.mail.Message; +import model.mail.Person; + +import java.util.ArrayList; + +public class Prank { + + private Person sender; + private ArrayList recipients; + private ArrayList witnesses; + + private Message message; + + private int groupId; + + public Person getSender() { + return sender; + } + + public void setSender(Person sender) { + this.sender = sender; + } + + public ArrayList getRecipients() { + return recipients; + } + + public void setRecipients(ArrayList recipients) { + this.recipients = recipients; + } + + public ArrayList getWitnesses() { + return witnesses; + } + + public void setWitnesses(ArrayList witnesses) { + this.witnesses = witnesses; + } + + public Message getMessage() { + return message; + } + + public void setMessage(Message message) { + this.message = message; + } + + public int getGroupId() { + return groupId; + } + + public void setGroupId(int groupId) { + this.groupId = groupId; + } +} diff --git a/src/main/java/model/prank/PrankGenerator.java b/src/main/java/model/prank/PrankGenerator.java new file mode 100644 index 0000000..c4c530d --- /dev/null +++ b/src/main/java/model/prank/PrankGenerator.java @@ -0,0 +1,151 @@ +package model.prank; + +import config.ConfigurationManager; +import config.MessageList; +import config.ServerProperties; +import config.VictimList; +import model.exception.GroupMinimumSizeException; +import model.exception.NoGroupCreated; +import model.mail.Group; +import model.mail.Message; +import model.mail.Person; +import utils.Utils; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Locale; + +import org.apache.commons.io.FileUtils; + +public class PrankGenerator { + private final static int MINIMUM_GROUP_SIZE = 3; + private final static String END_OF_GROUP = "=========="; + + private ServerProperties server; + private MessageList messages; + private VictimList victims; + + private Group[] groups; + + public PrankGenerator(ConfigurationManager config) { + server = config.getServerProperties(); + messages = config.getMessageList(); + victims = config.getVictimList(); + + groups = null; + } + + public ArrayList generatePranks() throws NoGroupCreated, IOException { + if(groups == null) { + throw new NoGroupCreated("Please form groups before generate pranks"); + } + + ArrayList pranks = new ArrayList<>(); + for(int i = 0; i < groups.length; i++) { + Prank p = new Prank(); + + int randomIndex = Utils.randInt(groups[i].size()); + Person sender = groups[i].getMember(randomIndex); + + ArrayList recipients = groups[i].getMembers(); + recipients.remove(randomIndex); + + p.setSender(sender); + p.setRecipients(recipients); + + Message message = messages.getRandomMessage(); + + message.setFrom(sender.getEmail()); + message.setTo(personsToEmails(recipients)); + if(!server.getEmailCCs()[0].equalsIgnoreCase("none")) { + message.setCc(new ArrayList<>(Arrays.asList(server.getEmailCCs()))); + } + p.setMessage(message); + + p.setGroupId(groups[i].getId()); + + pranks.add(p); + } + + createGroupFile(pranks); + + return pranks; + } + + public void generateGroups() throws GroupMinimumSizeException { + int nbVictims = victims.getSize(); + int nbGroups = server.getNbVictimGroups(); + + groups = new Group[nbGroups]; + + if(nbVictims % nbGroups < MINIMUM_GROUP_SIZE || nbVictims < nbGroups * MINIMUM_GROUP_SIZE) { + throw new GroupMinimumSizeException("Every group must be at least " + MINIMUM_GROUP_SIZE); + } + + int groupSize = (int) Math.ceil((double)nbVictims / nbGroups); + + ArrayList vL = victims.getList(); + + for(int i = 0, j = -1; i < nbVictims; i++) { + if(i % groupSize == 0) { + j++; + groups[j] = new Group(); + } + groups[j].addMember(vL.get(i)); + } + } + + private ArrayList personsToEmails(ArrayList persons) { + ArrayList res = new ArrayList<>(); + for(Person p : persons) { + res.add(p.getEmail()); + } + + return res; + } + + private void createGroupFile(ArrayList pranks) throws IOException { + File outDir = new File("out"); + if(!outDir.exists()) { + Files.createDirectory(Paths.get("out")); + } else { + File[] filesOut = outDir.listFiles(); + if(filesOut != null) { + for(File f : filesOut) { + if(f.isDirectory()) { + FileUtils.deleteDirectory(f); + } else { + f.delete(); + } + } + } + } + + PrintWriter writer = new PrintWriter( + new FileWriter(outDir.getPath() + "\\groups.utf8", StandardCharsets.UTF_8)); + + StringBuilder content = new StringBuilder(); + + for(Prank p : pranks) { + content.append("Group " + p.getGroupId() + "\r\n"); + content.append("From:" + p.getSender().getEmail() + "\r\n"); + content.append("To: " + "\r\n"); + for(Person r : p.getRecipients()) { + content.append("\t" + r.getEmail() + "\r\n"); + } + content.append("\r\n"); + content.append(END_OF_GROUP + "\r\n"); + } + + writer.println(content); + writer.flush(); + writer.close(); + } +} diff --git a/src/main/java/smtp/SmtpClient.java b/src/main/java/smtp/SmtpClient.java new file mode 100644 index 0000000..b4416f8 --- /dev/null +++ b/src/main/java/smtp/SmtpClient.java @@ -0,0 +1,94 @@ +package smtp; + +import model.exception.SmtpException; +import model.mail.Message; + +import java.io.*; +import java.net.Socket; +import java.nio.charset.StandardCharsets; + +public final class SmtpClient { + public static final String CMD_EHLO = "EHLO "; + public static final String CMD_MAIL_FROM = "MAIL FROM: "; + public static final String CMD_RCPT_TO = "RCPT TO: "; + public static final String CMD_DATA = "DATA"; + public static final String CMD_END_OF_DATA = "\r\n.\r\n"; + + private String serverAddress; + private int port; + + public SmtpClient(String smtpServerAddress, int port) { + serverAddress = smtpServerAddress; + this.port = port; + } + + public void sendMessage(Message message) throws IOException, SmtpException { + Socket clientSocket = new Socket(serverAddress, port); + PrintWriter writer = new PrintWriter( + new OutputStreamWriter(clientSocket.getOutputStream(), StandardCharsets.UTF_8), true); + BufferedReader reader = new BufferedReader( + new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8)); + + String line = reader.readLine(); + writer.print(CMD_EHLO + "localhost\r\n"); + writer.flush(); + + line = reader.readLine(); + if(!line.startsWith("250")) { + throw new SmtpException("Error : " + line); + } + + while(line.startsWith("250-")) { + line = reader.readLine(); + } + + writer.write(CMD_MAIL_FROM + message.getFrom() + "\r\n"); + writer.flush(); + + line = reader.readLine(); + if(!line.startsWith("250")) { + throw new SmtpException("Error : " + line); + } + + for(String t : message.getTo()) { + writer.write(CMD_RCPT_TO + t + "\r\n"); + writer.flush(); + + line = reader.readLine(); + if(!line.startsWith("250")) { + throw new SmtpException("Error : " + line); + } + } + + writer.write(CMD_DATA + "\r\n"); + writer.flush(); + line = reader.readLine(); + + writer.write("From: " + message.getFrom() + "\r\n"); + if(message.getCc() != null) { + writer.write("Cc: " + message.getCc() + "\r\n"); + } + writer.write("To: " + message.getTo().get(0) + "\r\n"); + for(int i = 1; i < message.getTo().size(); i++) { + writer.write(", " + message.getTo().get(i) + "\r\n"); + } + + writer.write("Subject: " + message.getSubject() + "\r\n"); + writer.write("\r\n"); + writer.write(message.getBody()); + writer.write(CMD_END_OF_DATA); + writer.flush(); + + line = reader.readLine(); + if(!line.startsWith("250")) { + throw new SmtpException("Error : " + line); + } + + writer.write("quit\r\n"); + writer.flush(); + + reader.close(); + writer.close(); + clientSocket.close(); + } +} \ No newline at end of file diff --git a/src/main/java/utils/Utils.java b/src/main/java/utils/Utils.java new file mode 100644 index 0000000..e61c99a --- /dev/null +++ b/src/main/java/utils/Utils.java @@ -0,0 +1,16 @@ +package utils; + +import java.util.Random; + +public class Utils { + + public static int randInt(int min, int max) { + Random rand = new Random(); + int randNum = rand.nextInt(max - min) + min; + return randNum; + } + + public static int randInt(int max) { + return randInt(0, max); + } +} From a2b44e13fd298e0f471e97da9bd3c22b24b75a71 Mon Sep 17 00:00:00 2001 From: Hoang Anh Mai Date: Sun, 2 May 2021 18:27:39 +0200 Subject: [PATCH 2/5] complete implementation --- data/config.properties | 6 +- src/main/java/Spammer.java | 4 +- src/main/java/config/MessageList.java | 8 ++- src/main/java/config/ServerProperties.java | 8 +-- src/main/java/model/mail/Message.java | 30 +--------- src/main/java/model/prank/Prank.java | 5 ++ src/main/java/model/prank/PrankGenerator.java | 40 ++++++------- src/main/java/smtp/SmtpClient.java | 57 +++++++++++++------ 8 files changed, 77 insertions(+), 81 deletions(-) diff --git a/data/config.properties b/data/config.properties index ce53f21..14708a8 100644 --- a/data/config.properties +++ b/data/config.properties @@ -1,5 +1,5 @@ smtpServerAddress=localhost smtpServerPort=25 -numberOfGroups=8 -chosenGroupsForPrank=1,3,8 -witnessesToCC=abd@def.com +numberOfGroups=6 +chosenGroupsForPrank=1,3 +witnessesToCC=NONE diff --git a/src/main/java/Spammer.java b/src/main/java/Spammer.java index dfad6bc..4ec8060 100644 --- a/src/main/java/Spammer.java +++ b/src/main/java/Spammer.java @@ -28,7 +28,7 @@ public static void main(String... args) throws EmptyList, IOException, Incorrect if(server.getChosenGroups()[0] == 0) { System.out.println("not"); for(Prank p : pranks) { - smtp.sendMessage(p.getMessage()); + smtp.sendMessage(p); } } else { System.out.println("inhere"); @@ -36,7 +36,7 @@ public static void main(String... args) throws EmptyList, IOException, Incorrect for(int i = 0; i < groups.length; i++) { int groupId = groups[i] - 1; if(groupId < nbGroups) { - smtp.sendMessage(pranks.get(groupId).getMessage()); + smtp.sendMessage(pranks.get(groupId)); } else { throw new IndexOutOfBoundsException("GroupId exceeds the number of groups"); } diff --git a/src/main/java/config/MessageList.java b/src/main/java/config/MessageList.java index aec264c..f9754d5 100644 --- a/src/main/java/config/MessageList.java +++ b/src/main/java/config/MessageList.java @@ -8,8 +8,7 @@ import java.nio.charset.StandardCharsets; public class MessageList { - private final static String END_OF_MESSAGE = "==========="; - private final static String MESSAGE_SUBJECT = "Subject"; + private final static String END_OF_MESSAGE = "(==========)"; private Message[] messages; private int nbMessages; @@ -46,14 +45,17 @@ private void addEachMessageToList(BufferedReader reader) throws IOException, Emp throw new EmptyList("There is no message in the file"); } - String[] splitedMessages = allMessages.toString().split("(==========)"); + String[] splitedMessages = allMessages.toString().split(END_OF_MESSAGE); nbMessages = splitedMessages.length; StringBuilder[] splitedMessagesBuilder = new StringBuilder[nbMessages]; splitedMessagesBuilder[0] = new StringBuilder(splitedMessages[0]); for(int i = 1; i < nbMessages; i++) { splitedMessagesBuilder[i] = new StringBuilder(splitedMessages[i]); + + //delete '\r' at the beginning of each message splitedMessagesBuilder[i].deleteCharAt(0); + //delete '\n' at the beginning of each message splitedMessagesBuilder[i].deleteCharAt(0); } diff --git a/src/main/java/config/ServerProperties.java b/src/main/java/config/ServerProperties.java index 4322b2e..66fec29 100644 --- a/src/main/java/config/ServerProperties.java +++ b/src/main/java/config/ServerProperties.java @@ -1,16 +1,10 @@ package config; -import model.exception.IncorrectFormatEmail; -import model.mail.Person; - import java.io.*; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.InputMismatchException; import java.util.Properties; public class ServerProperties { - private String filename; + private final String filename; private String serverAddress; private int serverPort; diff --git a/src/main/java/model/mail/Message.java b/src/main/java/model/mail/Message.java index 4da45a6..6a02939 100644 --- a/src/main/java/model/mail/Message.java +++ b/src/main/java/model/mail/Message.java @@ -3,38 +3,12 @@ import java.util.ArrayList; public class Message { - private String from; - private ArrayList to; - - private ArrayList cc = null; + public final static String contentType = "Content-Type: text/plain; charset=utf-8"; + public final static String CRLF = "\r\n"; private String subject; private String body; - public String getFrom() { - return from; - } - - public void setFrom(String from) { - this.from = from; - } - - public ArrayList getTo() { - return to; - } - - public void setTo(ArrayList to) { - this.to = to; - } - - public ArrayList getCc() { - return cc; - } - - public void setCc(ArrayList cc) { - this.cc = cc; - } - public String getSubject() { return subject; } diff --git a/src/main/java/model/prank/Prank.java b/src/main/java/model/prank/Prank.java index a6f9cf8..43f7186 100644 --- a/src/main/java/model/prank/Prank.java +++ b/src/main/java/model/prank/Prank.java @@ -54,4 +54,9 @@ public int getGroupId() { public void setGroupId(int groupId) { this.groupId = groupId; } + + public int numberOfMembers() { + // 1 represents number of senders + return recipients.size() + 1; + } } diff --git a/src/main/java/model/prank/PrankGenerator.java b/src/main/java/model/prank/PrankGenerator.java index c4c530d..d1aca8c 100644 --- a/src/main/java/model/prank/PrankGenerator.java +++ b/src/main/java/model/prank/PrankGenerator.java @@ -5,6 +5,7 @@ import config.ServerProperties; import config.VictimList; import model.exception.GroupMinimumSizeException; +import model.exception.IncorrectFormatEmail; import model.exception.NoGroupCreated; import model.mail.Group; import model.mail.Message; @@ -24,6 +25,8 @@ import org.apache.commons.io.FileUtils; +import static model.mail.Message.CRLF; + public class PrankGenerator { private final static int MINIMUM_GROUP_SIZE = 3; private final static String END_OF_GROUP = "=========="; @@ -42,7 +45,7 @@ public PrankGenerator(ConfigurationManager config) { groups = null; } - public ArrayList generatePranks() throws NoGroupCreated, IOException { + public ArrayList generatePranks() throws NoGroupCreated, IOException, IncorrectFormatEmail { if(groups == null) { throw new NoGroupCreated("Please form groups before generate pranks"); } @@ -60,13 +63,15 @@ public ArrayList generatePranks() throws NoGroupCreated, IOException { p.setSender(sender); p.setRecipients(recipients); - Message message = messages.getRandomMessage(); - - message.setFrom(sender.getEmail()); - message.setTo(personsToEmails(recipients)); if(!server.getEmailCCs()[0].equalsIgnoreCase("none")) { - message.setCc(new ArrayList<>(Arrays.asList(server.getEmailCCs()))); + ArrayList ccs = new ArrayList<>(); + for(String email : server.getEmailCCs()) { + ccs.add(new Person(email)); + } + p.setWitnesses(ccs); } + + Message message = messages.getRandomMessage(); p.setMessage(message); p.setGroupId(groups[i].getId()); @@ -86,7 +91,7 @@ public void generateGroups() throws GroupMinimumSizeException { groups = new Group[nbGroups]; if(nbVictims % nbGroups < MINIMUM_GROUP_SIZE || nbVictims < nbGroups * MINIMUM_GROUP_SIZE) { - throw new GroupMinimumSizeException("Every group must be at least " + MINIMUM_GROUP_SIZE); + throw new GroupMinimumSizeException("There is a group with size less than " + MINIMUM_GROUP_SIZE); } int groupSize = (int) Math.ceil((double)nbVictims / nbGroups); @@ -102,15 +107,6 @@ public void generateGroups() throws GroupMinimumSizeException { } } - private ArrayList personsToEmails(ArrayList persons) { - ArrayList res = new ArrayList<>(); - for(Person p : persons) { - res.add(p.getEmail()); - } - - return res; - } - private void createGroupFile(ArrayList pranks) throws IOException { File outDir = new File("out"); if(!outDir.exists()) { @@ -134,14 +130,14 @@ private void createGroupFile(ArrayList pranks) throws IOException { StringBuilder content = new StringBuilder(); for(Prank p : pranks) { - content.append("Group " + p.getGroupId() + "\r\n"); - content.append("From:" + p.getSender().getEmail() + "\r\n"); - content.append("To: " + "\r\n"); + content.append("Group " + p.getGroupId() + " - " + p.numberOfMembers() + " members" + CRLF); + content.append("From:" + p.getSender().getEmail() + CRLF); + content.append("To: " + CRLF); for(Person r : p.getRecipients()) { - content.append("\t" + r.getEmail() + "\r\n"); + content.append("\t" + r.getEmail() + CRLF); } - content.append("\r\n"); - content.append(END_OF_GROUP + "\r\n"); + content.append(CRLF); + content.append(END_OF_GROUP + CRLF); } writer.println(content); diff --git a/src/main/java/smtp/SmtpClient.java b/src/main/java/smtp/SmtpClient.java index b4416f8..2134dbd 100644 --- a/src/main/java/smtp/SmtpClient.java +++ b/src/main/java/smtp/SmtpClient.java @@ -2,17 +2,23 @@ import model.exception.SmtpException; import model.mail.Message; +import model.mail.Person; +import model.prank.Prank; import java.io.*; import java.net.Socket; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Base64; + +import static model.mail.Message.CRLF; public final class SmtpClient { public static final String CMD_EHLO = "EHLO "; public static final String CMD_MAIL_FROM = "MAIL FROM: "; public static final String CMD_RCPT_TO = "RCPT TO: "; public static final String CMD_DATA = "DATA"; - public static final String CMD_END_OF_DATA = "\r\n.\r\n"; + public static final String CMD_END_OF_DATA = CRLF + "." + CRLF; private String serverAddress; private int port; @@ -22,15 +28,23 @@ public SmtpClient(String smtpServerAddress, int port) { this.port = port; } - public void sendMessage(Message message) throws IOException, SmtpException { + public void sendMessage(Prank prank) throws IOException, SmtpException { Socket clientSocket = new Socket(serverAddress, port); PrintWriter writer = new PrintWriter( new OutputStreamWriter(clientSocket.getOutputStream(), StandardCharsets.UTF_8), true); BufferedReader reader = new BufferedReader( new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8)); + Message message = prank.getMessage(); + String sender = prank.getSender().getEmail(); + + ArrayList recipients = new ArrayList<>(); + for(Person p : prank.getRecipients()) { + recipients.add(p.getEmail()); + } + String line = reader.readLine(); - writer.print(CMD_EHLO + "localhost\r\n"); + writer.print(CMD_EHLO + "localhost" + CRLF); writer.flush(); line = reader.readLine(); @@ -42,7 +56,7 @@ public void sendMessage(Message message) throws IOException, SmtpException { line = reader.readLine(); } - writer.write(CMD_MAIL_FROM + message.getFrom() + "\r\n"); + writer.write(CMD_MAIL_FROM + sender + CRLF); writer.flush(); line = reader.readLine(); @@ -50,8 +64,8 @@ public void sendMessage(Message message) throws IOException, SmtpException { throw new SmtpException("Error : " + line); } - for(String t : message.getTo()) { - writer.write(CMD_RCPT_TO + t + "\r\n"); + for(String r : recipients) { + writer.write(CMD_RCPT_TO + r + CRLF); writer.flush(); line = reader.readLine(); @@ -60,21 +74,32 @@ public void sendMessage(Message message) throws IOException, SmtpException { } } - writer.write(CMD_DATA + "\r\n"); + writer.write(CMD_DATA + CRLF); writer.flush(); line = reader.readLine(); - writer.write("From: " + message.getFrom() + "\r\n"); - if(message.getCc() != null) { - writer.write("Cc: " + message.getCc() + "\r\n"); + writer.write("From: " + sender + CRLF); + + + if(prank.getWitnesses() != null) { + ArrayList ccs = new ArrayList<>(); + for(Person p : prank.getWitnesses()) { + ccs.add(p.getEmail()); + } + + writer.write("Cc: " + ccs.get(0) + CRLF); + for(int i = 1; i < ccs.size(); i++) { + writer.write(", " + ccs.get(i) + CRLF); + } } - writer.write("To: " + message.getTo().get(0) + "\r\n"); - for(int i = 1; i < message.getTo().size(); i++) { - writer.write(", " + message.getTo().get(i) + "\r\n"); + writer.write("To: " + recipients.get(0) + CRLF); + for(int i = 1; i < recipients.size(); i++) { + writer.write(", " + recipients.get(i) + CRLF); } - writer.write("Subject: " + message.getSubject() + "\r\n"); - writer.write("\r\n"); + writer.write("Subject: " + "=?utf-8?B?" + Base64.getEncoder().encodeToString(message.getSubject().getBytes()) + "?=" + CRLF); + writer.write(Message.contentType + CRLF); + writer.write(CRLF); writer.write(message.getBody()); writer.write(CMD_END_OF_DATA); writer.flush(); @@ -84,7 +109,7 @@ public void sendMessage(Message message) throws IOException, SmtpException { throw new SmtpException("Error : " + line); } - writer.write("quit\r\n"); + writer.write("quit" + CRLF); writer.flush(); reader.close(); From 1b8cbf8244c9567d9cb0f20185901013f83432db Mon Sep 17 00:00:00 2001 From: Hoang Anh Mai Date: Sun, 2 May 2021 22:50:44 +0200 Subject: [PATCH 3/5] final --- README.md | 68 ++++++++---------- data/config.properties | 2 +- figures/schema.png | Bin 0 -> 27117 bytes src/main/java/Spammer.java | 11 ++- .../java/config/ConfigurationManager.java | 6 +- src/main/java/config/ServerProperties.java | 7 ++ src/main/java/config/VictimList.java | 4 +- src/main/java/model/mail/Group.java | 10 +-- src/main/java/model/mail/Message.java | 2 - src/main/java/model/mail/Person.java | 2 +- src/main/java/model/prank/PrankGenerator.java | 34 +++++---- src/main/java/smtp/SmtpClient.java | 4 +- 12 files changed, 71 insertions(+), 79 deletions(-) create mode 100644 figures/schema.png diff --git a/README.md b/README.md index b5221f0..1cdbbad 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,53 @@ # Teaching-HEIGVD-RES-2021-Labo-SMTP -## Objectives +## Introduction -In this lab, you will develop a client application (TCP) in Java. This client application will use the Socket API to communicate with an SMTP server. The code that you write will include a **partial implementation of the SMTP protocol**. These are the objectives of the lab: +__Spammer__ is a prank-application. With a given victim list and a give number of groups, the application will send provided messages to victims by group with another victim email chosen randomly in each group. In other words, the goal is to mislead recipient victims into thinking that the sender victim has sent them. __Spammer__ uses the Socket API to communicate with an SMTP server with TCP connection in Java. (It is notable that the application is a **partial implementation of the SMTP protocol**.) -* Make practical experiments to become familiar with the **SMTP protocol**. After the lab, you should be able to use a command line tool to **communicate with an SMTP server**. You should be able to send well-formed messages to the server, in order to send people to the address of your choice. +## Instructions -* Understand the notions of **test double** and **mock server**, which are useful when developing and testing a client-server application. During the lab, you will setup and use such a **mock server**. +There are 3 configuration files in which you are free to set values as you want as long as these values obey their standard formats : -* Understand what it means to **implement the SMTP protocol** and be able to send e-model.mail messages, by working directly on top of the Socket API (i.e. you are not allowed to use a SMTP library). +1. __config.properties__: contains server properties. + * ___smtpServerAddress___ : determines SMTP server addresses. + * ___smtpServerPort___: determines SMTP server port. If the value less or equal than 0, the port will be 25 by default. + * ___numberOfGroups___: number of groups that you want to partition victim list. + * ___chosenGroupsForPrank___: groups of victims that you want to do the prank on. If the value is 0, the prank will be made on all groups. + * ___witnessesToCC___: CC email for the prank. If the value is `none`, the CC email will be considered as `null`. -* **See how easy it is to send forged e-mails**, which appear to be sent by certain people but in reality are issued by malicious users. +2. __messages.uft8__: contains given messages which will be encoded in `utf-8` of the prank. The file can contain multiple paragraphs. If there are 10 equal symbols (`==========`) separating them. All the paragraphs between these symbols represent a message. By convention, the first line of paragraph is the message subject and the rest is the message content. +3. __victims.uft8__: contains a victim email list also provided and encoded in `utf-8`. This list will be partitioned into small groups. Note that in every group of victims, there should be 1 sender and at least 2 recipients (i.e. the minimum size for a group is 3). In the file, each line must contain exactly one victim email address. -* **Design a simple object-oriented model** to implement the functional requirements described in the next paragraph. +All these files are found in `data` folder. +On the other hand, once the groups are created. They will be written in `groups.utf8` file, which can be found in `target/out/`. In this file, you'll find who the sender of each group and his recipients. Each group is separated by 10 equal symbols (`==========`). -## Functional requirements +The application will choose randomly a message and a sender for each group. -Your mission is to develop a client application that automatically plays pranks on a list of victims: +## Mock SMTP server -* The user should be able to **define a list of victims** (concretely, you should be able to create a file containing a list of e-model.mail addresses). -* The user should be able to **define how many groups of victims should be formed** in a given campaign. In every model.mail of victims, there should be 1 sender and at least 2 recipients (i.e. the minimum size for a model.mail is 3). -* The user should be able to **define a list of e-model.mail messages**. When a prank is played on a model.mail of victims, then one of these messages should be selected. **The model.mail should be sent to all model.mail recipients, from the address of the model.mail sender**. In other words, the recipient victims should be lead to believe that the sender victim has sent them. +This section is for those who want to experiment with __Spammer__ but don't really want to send pranks immediately. -## Constraints +First of all, you will need to simulate a ___fake___ SMTP server, i.e., mock SMTP server. +> A [MockServer]() is designed to simplify integration testing and promotes best practices by improving the isolation of the system under test. -- The goal is for you to work at the wire protocol level (with the Socket API). Therefore, you CANNOT use a library that takes care of the protocol details. You have to work with the input and output streams. -- The program must be configurable: the addresses, groups, messages CANNOT be hard-coded in the program and MUST be managed in config files. +In order to do that, you can use any mock SMTP server on the internet. Here, we'll use [MockMock server]() on GitHub, which is a web-application. The executable `jar` file can be easily downloaded by following the instructions in `README.md` of [MockMock server]() or retrieved by cloning the repository then building application. For any further information, you can checkout [MockMock server]() repository. +Once you have extracted the executable file to any place that you like, you can start the server by running: `java -jar MockMock.jar`. Note that with this command, the port is 25 by default. To run MockMock on another port, you can start it with the following parameters: `java -jar MockMock.jar -p 25000 -h 8080`. This will run MockMock on SMTP port 25000 and http port 8080. After that, you can go to your browser and type `localhost:8282`. This will show you the web interface of MockMock. -## Example +You can now launch __Spammer__ which will read your configuration in 3 files mentioned above. After refreshing the browser you'll see the prank made on your victim list. -Consider that your program generates a model.mail G1. The model.mail sender is Bob. The model.mail recipients are Alice, Claire and Peter. When the prank is played on model.mail G1, then your program should pick one of the fake messages. It should communicate with an SMTP server, so that Alice, Claire and Peter receive an e-model.mail, which appears to be sent by Bob. +## Description of implementation +![Simplified UML of __Spammer__](figures/schema.jpg?raw=true "Simplified UML of __Spammer__ without Utils and Exceptions") -## Teams +The logic of the application remains in 2 classes: `ConfigurationManager` and `PrankGenerator`. -You may work in teams of 2 students. +The first class is responsible for reading configuration files in __Instruction__ section. For the messages, it will call create a `MessageList` to obtain messages in the message file by reading all characters in the file (Remember that each message is separated by 10 equal symbols (`==========`)), then, split the result string by the convention separation into substrings, which are the messages. For the victims, the principle is as same as for the messages, `ConfigurationManager` creates a `VictimList`, which save the victims by reading the victim file line by line. For the server properties, `ConfigurationManager` creates a `ServerProperties` to set up the server with the help of `Properties`. -## Deliverables +The second class is used for partitioning the victim list and generating mails/pranks based on configurations above. The partition is quite easy. It just creates groups with size of victim list divided by the given number of groups. Then, for each group, it will randomly choose a victim sender and recipient and also a message for each prank. -You will deliver the results of your lab in a GitHub repository. You do not have to fork a specific repo, you can create one from scratch. - -Your repository should contain both the source code of your Java project and your report. Your report should be a single `README.md` file, located at the root of your repository. The images should be placed in a `figures` directory. - -Your report MUST include the following sections: - -* **A brief description of your project**: if people exploring GitHub find your repo, without a prior knowledge of the RES course, they should be able to understand what your repo is all about and whether they should look at it more closely. - -* **Instructions for setting up a mock SMTP server (with Docker - which you will learn all about in the next 2 weeks)**. The user who wants to experiment with your tool but does not really want to send pranks immediately should be able to use a mock SMTP server. For people who are not familiar with this concept, explain it to them in simple terms. Explain which mock server you have used and how you have set it up. - -* **Clear and simple instructions for configuring your tool and running a prank campaign**. If you do a good job, an external user should be able to clone your repo, edit a couple of files and send a batch of e-mails in less than 10 minutes. - -* **A description of your implementation**: document the key aspects of your code. It is probably a good idea to start with a class diagram. Decide which classes you want to show (focus on the important ones) and describe their responsibilities in text. It is also certainly a good idea to include examples of dialogues between your client and an SMTP server (maybe you also want to include some screenshots here). ## References -* [MockMock server]() on GitHub. Pay attention to this [pull request](https://github.com/tweakers/MockMock/pull/8). While it has not been merged, it will give you the solution to compile the project on your machine. -* The [mailtrap]() online service for testing SMTP -* The [SMTP RFC](), and in particular the [example scenario]() -* Testing SMTP with TLS: `openssl s_client -connect smtp.mailtrap.io:2525 -starttls smtp -crlf` - +* [MockMock server]() on GitHub +* [MockServer]() on Wikipedia +* [Regex for email]() diff --git a/data/config.properties b/data/config.properties index 14708a8..3a0a4bd 100644 --- a/data/config.properties +++ b/data/config.properties @@ -1,5 +1,5 @@ smtpServerAddress=localhost smtpServerPort=25 numberOfGroups=6 -chosenGroupsForPrank=1,3 +chosenGroupsForPrank=0 witnessesToCC=NONE diff --git a/figures/schema.png b/figures/schema.png new file mode 100644 index 0000000000000000000000000000000000000000..8730c62af28778567d0d23bdb38de754d883ed95 GIT binary patch literal 27117 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 literal 0 HcmV?d00001 diff --git a/src/main/java/Spammer.java b/src/main/java/Spammer.java index 4ec8060..915553a 100644 --- a/src/main/java/Spammer.java +++ b/src/main/java/Spammer.java @@ -1,7 +1,6 @@ import config.ConfigurationManager; import config.ServerProperties; import model.exception.*; -import model.mail.Person; import model.prank.Prank; import model.prank.PrankGenerator; import smtp.SmtpClient; @@ -26,16 +25,14 @@ public static void main(String... args) throws EmptyList, IOException, Incorrect SmtpClient smtp = new SmtpClient(address, port); if(server.getChosenGroups()[0] == 0) { - System.out.println("not"); for(Prank p : pranks) { smtp.sendMessage(p); } } else { - System.out.println("inhere"); - int[] groups = server.getChosenGroups(); - for(int i = 0; i < groups.length; i++) { - int groupId = groups[i] - 1; - if(groupId < nbGroups) { + int[] ids = server.getChosenGroups(); + for (int id : ids) { + int groupId = id - 1; + if (groupId < nbGroups) { smtp.sendMessage(pranks.get(groupId)); } else { throw new IndexOutOfBoundsException("GroupId exceeds the number of groups"); diff --git a/src/main/java/config/ConfigurationManager.java b/src/main/java/config/ConfigurationManager.java index 35b236f..77d40ec 100644 --- a/src/main/java/config/ConfigurationManager.java +++ b/src/main/java/config/ConfigurationManager.java @@ -6,9 +6,9 @@ import java.io.IOException; public class ConfigurationManager { - private ServerProperties serverProperties; - private MessageList messageList; - private VictimList victimList; + private final ServerProperties serverProperties; + private final MessageList messageList; + private final VictimList victimList; public ConfigurationManager() throws EmptyList, IOException, IncorrectFormatEmail { serverProperties = new ServerProperties("data/config.properties"); diff --git a/src/main/java/config/ServerProperties.java b/src/main/java/config/ServerProperties.java index 66fec29..63991c7 100644 --- a/src/main/java/config/ServerProperties.java +++ b/src/main/java/config/ServerProperties.java @@ -4,6 +4,8 @@ import java.util.Properties; public class ServerProperties { + private final static int DEFAULT_PORT = 25; + private final String filename; private String serverAddress; @@ -23,7 +25,12 @@ public void loadFromFile() throws IOException { serverConfig.load(input); serverAddress = serverConfig.getProperty("smtpServerAddress"); + serverPort = Integer.parseInt(serverConfig.getProperty("smtpServerPort")); + if(serverPort <= 0) { + serverPort = DEFAULT_PORT; + } + nbVictimGroups = Integer.parseInt(serverConfig.getProperty("numberOfGroups")); emailCCs = serverConfig.getProperty("witnessesToCC").split(","); diff --git a/src/main/java/config/VictimList.java b/src/main/java/config/VictimList.java index fe66262..9f65a8d 100644 --- a/src/main/java/config/VictimList.java +++ b/src/main/java/config/VictimList.java @@ -9,8 +9,8 @@ import java.util.ArrayList; public class VictimList { - private ArrayList people; - private int sizeList; + private final ArrayList people; + private final int sizeList; public VictimList(String filename) throws IOException, IncorrectFormatEmail, EmptyList { people = new ArrayList<>(); diff --git a/src/main/java/model/mail/Group.java b/src/main/java/model/mail/Group.java index 1c89c63..25b2d88 100644 --- a/src/main/java/model/mail/Group.java +++ b/src/main/java/model/mail/Group.java @@ -5,7 +5,7 @@ public class Group { private static int nbGroups = 0; - private int id; + private final int id; private ArrayList members; public Group() { @@ -35,12 +35,12 @@ public int size() { @Override public String toString() { - String res = "Group " + id + "\r\n"; - res += "Members :" + "\r\n"; + StringBuilder res = new StringBuilder("Group " + id + "\r\n"); + res.append("Members :" + "\r\n"); for(Person p : members) { - res += p + "\r\n"; + res.append(p).append("\r\n"); } - return res; + return res.toString(); } } diff --git a/src/main/java/model/mail/Message.java b/src/main/java/model/mail/Message.java index 6a02939..b8cf10b 100644 --- a/src/main/java/model/mail/Message.java +++ b/src/main/java/model/mail/Message.java @@ -1,7 +1,5 @@ package model.mail; -import java.util.ArrayList; - public class Message { public final static String contentType = "Content-Type: text/plain; charset=utf-8"; public final static String CRLF = "\r\n"; diff --git a/src/main/java/model/mail/Person.java b/src/main/java/model/mail/Person.java index 8172391..a63b0ec 100644 --- a/src/main/java/model/mail/Person.java +++ b/src/main/java/model/mail/Person.java @@ -3,7 +3,7 @@ import model.exception.IncorrectFormatEmail; public class Person { - private String email; + private final String email; public Person(String email) throws IncorrectFormatEmail { if(!correctFormatEmail(email)) { diff --git a/src/main/java/model/prank/PrankGenerator.java b/src/main/java/model/prank/PrankGenerator.java index d1aca8c..88c60f0 100644 --- a/src/main/java/model/prank/PrankGenerator.java +++ b/src/main/java/model/prank/PrankGenerator.java @@ -20,8 +20,6 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; import org.apache.commons.io.FileUtils; @@ -31,9 +29,9 @@ public class PrankGenerator { private final static int MINIMUM_GROUP_SIZE = 3; private final static String END_OF_GROUP = "=========="; - private ServerProperties server; - private MessageList messages; - private VictimList victims; + private final ServerProperties server; + private final MessageList messages; + private final VictimList victims; private Group[] groups; @@ -51,21 +49,21 @@ public ArrayList generatePranks() throws NoGroupCreated, IOException, Inc } ArrayList pranks = new ArrayList<>(); - for(int i = 0; i < groups.length; i++) { + for (Group group : groups) { Prank p = new Prank(); - int randomIndex = Utils.randInt(groups[i].size()); - Person sender = groups[i].getMember(randomIndex); + int randomIndex = Utils.randInt(group.size()); + Person sender = group.getMember(randomIndex); - ArrayList recipients = groups[i].getMembers(); + ArrayList recipients = group.getMembers(); recipients.remove(randomIndex); p.setSender(sender); p.setRecipients(recipients); - if(!server.getEmailCCs()[0].equalsIgnoreCase("none")) { + if (!server.getEmailCCs()[0].equalsIgnoreCase("none")) { ArrayList ccs = new ArrayList<>(); - for(String email : server.getEmailCCs()) { + for (String email : server.getEmailCCs()) { ccs.add(new Person(email)); } p.setWitnesses(ccs); @@ -74,7 +72,7 @@ public ArrayList generatePranks() throws NoGroupCreated, IOException, Inc Message message = messages.getRandomMessage(); p.setMessage(message); - p.setGroupId(groups[i].getId()); + p.setGroupId(group.getId()); pranks.add(p); } @@ -108,9 +106,9 @@ public void generateGroups() throws GroupMinimumSizeException { } private void createGroupFile(ArrayList pranks) throws IOException { - File outDir = new File("out"); + File outDir = new File("target\\out"); if(!outDir.exists()) { - Files.createDirectory(Paths.get("out")); + Files.createDirectory(Paths.get("target\\out")); } else { File[] filesOut = outDir.listFiles(); if(filesOut != null) { @@ -130,11 +128,11 @@ private void createGroupFile(ArrayList pranks) throws IOException { StringBuilder content = new StringBuilder(); for(Prank p : pranks) { - content.append("Group " + p.getGroupId() + " - " + p.numberOfMembers() + " members" + CRLF); - content.append("From:" + p.getSender().getEmail() + CRLF); - content.append("To: " + CRLF); + content.append("Group ").append(p.getGroupId()).append(" - ").append(p.numberOfMembers()).append(" members").append(CRLF); + content.append("From: ").append(p.getSender().getEmail()).append(CRLF); + content.append("To:" + CRLF); for(Person r : p.getRecipients()) { - content.append("\t" + r.getEmail() + CRLF); + content.append("\t").append(r.getEmail()).append(CRLF); } content.append(CRLF); content.append(END_OF_GROUP + CRLF); diff --git a/src/main/java/smtp/SmtpClient.java b/src/main/java/smtp/SmtpClient.java index 2134dbd..d0066ba 100644 --- a/src/main/java/smtp/SmtpClient.java +++ b/src/main/java/smtp/SmtpClient.java @@ -20,8 +20,8 @@ public final class SmtpClient { public static final String CMD_DATA = "DATA"; public static final String CMD_END_OF_DATA = CRLF + "." + CRLF; - private String serverAddress; - private int port; + private final String serverAddress; + private final int port; public SmtpClient(String smtpServerAddress, int port) { serverAddress = smtpServerAddress; From 334f1ae9cf486f733f54a005cc4ad250c5e8b4f0 Mon Sep 17 00:00:00 2001 From: Hoang Anh Mai Date: Sun, 2 May 2021 22:51:59 +0200 Subject: [PATCH 4/5] final --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1cdbbad..8f4fcf1 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Once you have extracted the executable file to any place that you like, you can You can now launch __Spammer__ which will read your configuration in 3 files mentioned above. After refreshing the browser you'll see the prank made on your victim list. ## Description of implementation -![Simplified UML of __Spammer__](figures/schema.jpg?raw=true "Simplified UML of __Spammer__ without Utils and Exceptions") +![Simplified UML of __Spammer__](https://github.com/mhganh/Teaching-HEIGVD-RES-2021-Labo-SMTP/tree/main/figures/schema.jpg?raw=true "Simplified UML of __Spammer__ without Utils and Exceptions") The logic of the application remains in 2 classes: `ConfigurationManager` and `PrankGenerator`. From 44015a1ef8f071afa979017a4c8f0e0dd2429f69 Mon Sep 17 00:00:00 2001 From: Hoang Anh Mai Date: Sun, 2 May 2021 22:53:26 +0200 Subject: [PATCH 5/5] final --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f4fcf1..38691b7 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Once you have extracted the executable file to any place that you like, you can You can now launch __Spammer__ which will read your configuration in 3 files mentioned above. After refreshing the browser you'll see the prank made on your victim list. ## Description of implementation -![Simplified UML of __Spammer__](https://github.com/mhganh/Teaching-HEIGVD-RES-2021-Labo-SMTP/tree/main/figures/schema.jpg?raw=true "Simplified UML of __Spammer__ without Utils and Exceptions") +![Simplified UML of __Spammer__](https://github.com/mhganh/Teaching-HEIGVD-RES-2021-Labo-SMTP/tree/main/figures/schema.png?raw=true "Simplified UML of __Spammer__ without Utils and Exceptions") The logic of the application remains in 2 classes: `ConfigurationManager` and `PrankGenerator`.