Browse Source

Architecture improvements and validation

Improved system architecture and added sample regex validation to
registration
master
Rohan Sircar 5 years ago
parent
commit
acbacc8fa8
  1. 19
      chatto/pom.xml
  2. 2
      chatto/src/main/java/org/ros/chatto/RESTAuthenticationEntryPoint.java
  3. 21
      chatto/src/main/java/org/ros/chatto/controller/AdminController.java
  4. 87
      chatto/src/main/java/org/ros/chatto/controller/AdminRESTController.java
  5. 49
      chatto/src/main/java/org/ros/chatto/controller/ChatMessageController.java
  6. 53
      chatto/src/main/java/org/ros/chatto/controller/DemoRestController.java
  7. 31
      chatto/src/main/java/org/ros/chatto/controller/RegistrationController.java
  8. 2
      chatto/src/main/java/org/ros/chatto/dto/ChatMessageDTO.java
  9. 25
      chatto/src/main/java/org/ros/chatto/dto/MessageCipherDTO.java
  10. 14
      chatto/src/main/java/org/ros/chatto/dto/ReencryptionDTO.java
  11. 14
      chatto/src/main/java/org/ros/chatto/dto/UserPublicDTO.java
  12. 16
      chatto/src/main/java/org/ros/chatto/dto/UserRegistrationDTO.java
  13. 21
      chatto/src/main/java/org/ros/chatto/model/ApplicationStatus.java
  14. 2
      chatto/src/main/java/org/ros/chatto/model/MessageCipher.java
  15. 12
      chatto/src/main/java/org/ros/chatto/repository/ChatMessageRepository.java
  16. 3
      chatto/src/main/java/org/ros/chatto/repository/UserRoleRepository.java
  17. 25
      chatto/src/main/java/org/ros/chatto/service/ChatService.java
  18. 38
      chatto/src/main/java/org/ros/chatto/service/ChatServiceImpl.java
  19. 60
      chatto/src/main/java/org/ros/chatto/service/DBInitializerService.java
  20. 42
      chatto/src/main/java/org/ros/chatto/service/MyConversionService.java
  21. 1
      chatto/src/main/java/org/ros/chatto/service/UserService.java
  22. 6
      chatto/src/main/java/org/ros/chatto/service/UserServiceImpl.java
  23. 3
      chatto/src/main/resources/queries.properties
  24. 135
      chatto/src/main/resources/static/js/admin.js
  25. 396
      chatto/src/main/resources/static/js/chat.js
  26. 109
      chatto/src/main/resources/templates/admin/home.html
  27. 18
      chatto/src/main/resources/templates/chat.html
  28. 20
      chatto/src/main/resources/templates/fragments/navbar.html
  29. 13
      chatto/src/main/resources/templates/home.html
  30. 2
      chatto/src/main/resources/templates/login.html
  31. 77
      chatto/src/main/resources/templates/registration.html

19
chatto/pom.xml

@ -100,18 +100,20 @@
<artifactId>cache-api</artifactId>
</dependency>
<!-- <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId>
<version>2.2.11</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId> <version>2.2.11</version> </dependency> -->
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity5 -->
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity5 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
@ -124,6 +126,7 @@
<!-- <dependency> <groupId>javax.cache</groupId> <artifactId>cache-api</artifactId>
<version>1.1.0</version> </dependency> -->
</dependencies>
<build>

2
chatto/src/main/java/org/ros/chatto/RESTAuthenticationEntryPoint.java

@ -31,7 +31,7 @@ public final class RESTAuthenticationEntryPoint
response.addHeader("WWW-Authenticate", "Basic realm=" +getRealmName());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter writer = response.getWriter();
writer.println("HTTP Status 401 - " + authEx.getMessage());
writer.println("HTTP ApplicationStatus 401 - " + authEx.getMessage());
}
@Override

21
chatto/src/main/java/org/ros/chatto/controller/AdminController.java

@ -1,14 +1,25 @@
package org.ros.chatto.controller;
import java.security.Principal;
import org.ros.chatto.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/admin")
public class AdminController {
@RequestMapping
public String viewManageUsers() {
return "/admin/home";
}
@Autowired
private UserService userService;
@RequestMapping
public ModelAndView viewManageUsers(Principal principal) {
ModelAndView modelAndView = new ModelAndView("/admin/home");
modelAndView.addObject("user", new String());
modelAndView.addObject("userNames", userService.getAllRegularUsers());
return modelAndView;
}
}

87
chatto/src/main/java/org/ros/chatto/controller/AdminRESTController.java

@ -0,0 +1,87 @@
package org.ros.chatto.controller;
import java.security.Principal;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Date;
import java.util.List;
import org.ros.chatto.dto.ChatMessageDTO;
import org.ros.chatto.dto.ReencryptionDTO;
import org.ros.chatto.model.ChatMessage;
import org.ros.chatto.service.ChatService;
import org.ros.chatto.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/admin")
public class AdminRESTController {
@Autowired
private ChatService chatService;
@Autowired
private UserService userService;
@PostMapping(value = "/post/re-encrypt", consumes = { "application/json" })
@ResponseBody
public ResponseEntity<ReencryptionDTO> reencryptMessages(@RequestBody List<ReencryptionDTO> reencryptionDTOs,
Principal principal) {
if (reencryptionDTOs.size() > 0) {
chatService.reencryptMessages(reencryptionDTOs);
}
return new ResponseEntity<ReencryptionDTO>(HttpStatus.OK);
}
@GetMapping(value = "/get/messages/{userName}")
@ResponseBody
public List<ReencryptionDTO> sendAllMessages(@PathVariable String userName, Principal principal) {
List<ReencryptionDTO> reencryptionDTOs = chatService.getAllMessagesForReencryption(principal.getName(), userName);
return reencryptionDTOs;
}
@GetMapping(value = "/get/messages/{userName}/{lastMessageTime}")
@ResponseBody
public List<ChatMessageDTO> sendNewMessages(@PathVariable String userName, @PathVariable String lastMessageTime,
Principal principal) {
System.out.println("Last message time = " + lastMessageTime);
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// offset (hh:mm - "+00:00" when it's zero)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
// offset (hhmm - "+0000" when it's zero)
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
// offset (hh - "Z" when it's zero)
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
// create formatter
.toFormatter();
Date date = Date.from(OffsetDateTime.parse(lastMessageTime, formatter).toInstant());
List<ChatMessageDTO> chatMessageDTOs = chatService.getNewMessages(principal.getName(), userName, date);
return chatMessageDTOs;
}
@GetMapping("/get/users")
public List<String> getAllOtherUsers(Principal principal) {
return userService.findAllOtherUsers(principal.getName());
}
}
//public ResponseEntity<List<ChatMessage>> getMessages(@PathVariable String userName, Principal principal) {
////List<ChatMessage> chatMessages = chatMessageRepository.getAllMessages(principal.getName(), userName);
//
//// return posts.stream()
//// .map(post -> convertToDto(post))
//// .collect(Collectors.toList());
//return new ResponseEntity<List<ChatMessage>>(chatMessages, HttpStatus.OK);
//}

49
chatto/src/main/java/org/ros/chatto/controller/ChatMessageController.java

@ -8,6 +8,8 @@ import java.util.Date;
import java.util.List;
import org.ros.chatto.dto.ChatMessageDTO;
import org.ros.chatto.dto.MessageCipherDTO;
import org.ros.chatto.dto.ReencryptionDTO;
import org.ros.chatto.model.MessageCipher;
import org.ros.chatto.service.ChatService;
import org.ros.chatto.service.UserService;
@ -19,6 +21,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@ -27,14 +30,14 @@ import org.springframework.web.bind.annotation.RestController;
public class ChatMessageController {
@Autowired
private ChatService chatService;
@Autowired
private UserService userService;
@PostMapping(value = "/post/message", consumes = { "application/json" })
@ResponseBody
public ResponseEntity<ChatMessageDTO> newMessage(@RequestBody ChatMessageDTO chatMessageDTO, Principal principal) {
MessageCipher messageCipher = chatMessageDTO.getMessageCipher();
MessageCipherDTO messageCipher = chatMessageDTO.getMessageCipher();
String fromUser = principal.getName();
String toUser = chatMessageDTO.getToUser();
System.out.println("Message cipher = " + messageCipher);
@ -46,31 +49,41 @@ public class ChatMessageController {
@ResponseBody
public List<ChatMessageDTO> sendAllMessages(@PathVariable String userName, Principal principal) {
List<ChatMessageDTO> chatMessageDTOs = chatService.getAllMessages(principal.getName(), userName);
return chatMessageDTOs;
return chatMessageDTOs;
}
@GetMapping(value = "/get/messages/{userName}", params = { "page", "size" })
@ResponseBody
public List<ChatMessageDTO> findPaginated(@RequestParam("page") int page, @RequestParam("size") int size,
@PathVariable String userName, Principal principal) {
List<ChatMessageDTO> chatMessageDTOs = chatService.getMessagePage(principal.getName(), userName, page, size);
return chatMessageDTOs;
}
@GetMapping(value = "/get/messages/{userName}/{lastMessageTime}")
@ResponseBody
public List<ChatMessageDTO> sendNewMessages(@PathVariable String userName, @PathVariable String lastMessageTime, Principal principal) {
System.out.println("Last message time = " + lastMessageTime );
public List<ChatMessageDTO> sendNewMessages(@PathVariable String userName, @PathVariable String lastMessageTime,
Principal principal) {
System.out.println("Last message time = " + lastMessageTime);
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// offset (hh:mm - "+00:00" when it's zero)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
// offset (hhmm - "+0000" when it's zero)
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
// offset (hh - "Z" when it's zero)
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
// create formatter
.toFormatter();
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// offset (hh:mm - "+00:00" when it's zero)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
// offset (hhmm - "+0000" when it's zero)
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
// offset (hh - "Z" when it's zero)
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
// create formatter
.toFormatter();
Date date = Date.from(OffsetDateTime.parse(lastMessageTime, formatter).toInstant());
List<ChatMessageDTO> chatMessageDTOs = chatService.getNewMessages(principal.getName(), userName, date);
return chatMessageDTOs;
return chatMessageDTOs;
}
@GetMapping("/get/users")
public List<String> getAllOtherUsers(Principal principal)
{
public List<String> getAllOtherUsers(Principal principal) {
return userService.findAllOtherUsers(principal.getName());
}
}

53
chatto/src/main/java/org/ros/chatto/controller/DemoRestController.java

@ -62,31 +62,33 @@ public class DemoRestController {
public ChatUser getUser() {
return userRepository.findByUserName("hmm");
}
@GetMapping("/user")
public ChatUser currentUserName(Principal principal) {
ChatUser user = userRepository.findByUserName(principal.getName());
return user;
}
return user;
}
@GetMapping("/roles")
public List<UserRole> getAllRoles()
{
public List<UserRole> getAllRoles() {
return userRoleRepository.findAll();
}
@GetMapping("/ciphers")
public List<MessageCipher> getAllCiphers()
{
public List<MessageCipher> getAllCiphers() {
return messageCipherRepository.findAll();
}
@GetMapping("/messages")
public List<ChatMessage> getAllMessages()
{
public List<ChatMessage> getAllMessages() {
return chatMessageRepository.findAll();
}
@GetMapping("/regular-users")
public List<String> getAllRegularUsers() {
return userRoleRepository.getAllRegularUser();
}
// @RequestMapping(value = "/", method = RequestMethod.POST)
// public ResponseEntity<Car> update(@RequestBody Car car) {
//
@ -97,28 +99,27 @@ public class DemoRestController {
// // TODO: call persistence layer to update
// return new ResponseEntity<Car>(car, HttpStatus.OK);
// }
@PostMapping(value="/post-message", consumes = {"application/json"})
public ResponseEntity<MessageCipher> postMessage(@RequestBody MessageCipher messageCipher)
{
@PostMapping(value = "/post-message", consumes = { "application/json" })
public ResponseEntity<MessageCipher> postMessage(@RequestBody MessageCipher messageCipher) {
System.out.println("Message cipher = " + messageCipher);
messageCipherRepository.save(messageCipher);
return new ResponseEntity<MessageCipher>(HttpStatus.OK);
}
@GetMapping("/logout")
public ModelAndView logoutPage()
{
public ModelAndView logoutPage() {
ModelAndView modelAndView = new ModelAndView("restLogout");
return modelAndView;
}
@RequestMapping(value="perform_logout", method = RequestMethod.POST)
public String performLogout (HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/users";
@RequestMapping(value = "perform_logout", method = RequestMethod.POST)
public String performLogout(HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/users";
}
}

31
chatto/src/main/java/org/ros/chatto/controller/RegistrationController.java

@ -1,34 +1,37 @@
package org.ros.chatto.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.ros.chatto.dto.UserRegistrationDTO;
import org.ros.chatto.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class RegisterController {
public class RegistrationController {
@Autowired
private UserService userService;
@GetMapping("/registration")
public ModelAndView registrationForm()
{
ModelAndView modelAndView = new ModelAndView("registration");
modelAndView.addObject("userDTO",new UserRegistrationDTO());
return modelAndView;
public String registrationForm(Model model) {
model.addAttribute("userRegistrationDTO", new UserRegistrationDTO());
return "registration";
}
@PostMapping("/perform_registration")
public ModelAndView performRegistration(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, @ModelAttribute("userDTO") UserRegistrationDTO userRegistrationDTO)
{
ModelAndView modelAndView = new ModelAndView("user/home");
public String performRegistration(Model model,
@ModelAttribute("userRegistrationDTO") @Valid UserRegistrationDTO userRegistrationDTO, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
System.out.println("Input has errors!");
return "registration";
}
userService.registerUser(userRegistrationDTO);
return modelAndView;
return "user/home";
}
}

2
chatto/src/main/java/org/ros/chatto/dto/ChatMessageDTO.java

@ -9,6 +9,6 @@ import lombok.Data;
@Data
public class ChatMessageDTO {
private String toUser, fromUser;
private MessageCipher messageCipher;
private MessageCipherDTO messageCipher;
private Date messageTime;
}

25
chatto/src/main/java/org/ros/chatto/dto/MessageCipherDTO.java

@ -0,0 +1,25 @@
package org.ros.chatto.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class MessageCipherDTO {
private String iv;
private int v;
@JsonProperty("iter")
private int iterations;
@JsonProperty("ks")
private int keySize;
@JsonProperty("ts")
private int tagSize;
private String mode;
private String adata;
private String cipher;
private String salt;
@JsonProperty("ct")
private String cipherText;
}

14
chatto/src/main/java/org/ros/chatto/dto/ReencryptionDTO.java

@ -0,0 +1,14 @@
package org.ros.chatto.dto;
import java.util.Date;
import org.ros.chatto.model.MessageCipher;
import lombok.Data;
@Data
public class ReencryptionDTO {
private String toUser, fromUser;
private MessageCipher messageCipher;
private Date messageTime;
}

14
chatto/src/main/java/org/ros/chatto/dto/UserPublicDTO.java

@ -1,14 +0,0 @@
package org.ros.chatto.dto;
import java.sql.Date;
import org.ros.chatto.model.MessageCipher;
import lombok.Data;
@Data
public class UserPublicDTO {
String fromUser, toUser;
MessageCipher messageCipher;
Date messageTime;
}

16
chatto/src/main/java/org/ros/chatto/dto/UserRegistrationDTO.java

@ -1,23 +1,35 @@
package org.ros.chatto.dto;
import javax.persistence.Transient;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
public class UserRegistrationDTO {
@Size(min = 4, max = 10, message = "Username must be between 4 and 10 characters")
@NotBlank(message = " Username should not be blank")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "Username must be alphanumeric")
private String userName;
@Transient
@Size(min = 4, max = 75, message = "Username must be between 4 and 75 characters")
@NotBlank(message = " Password should not be blank")
@Pattern(regexp = "^.*(?=.{6,})(?=.*d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$", message = "Invalid password format")
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

21
chatto/src/main/java/org/ros/chatto/model/ApplicationStatus.java

@ -0,0 +1,21 @@
package org.ros.chatto.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter
@Setter
@Table(name="status")
public class ApplicationStatus {
@Id
private int id;
private String name;
@Column(name="value")
private boolean done;
}

2
chatto/src/main/java/org/ros/chatto/model/MessageCipher.java

@ -20,7 +20,7 @@ this is what the json will look like*/
@Entity
@Table(name = "message_ciphers")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = { "id"}, allowGetters = false)
//@JsonIgnoreProperties(value = { "id"}, allowGetters = false)
public class MessageCipher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)

12
chatto/src/main/java/org/ros/chatto/repository/ChatMessageRepository.java

@ -1,9 +1,11 @@
package org.ros.chatto.repository;
import java.awt.print.Pageable;
import java.util.Date;
import java.util.List;
import org.ros.chatto.model.ChatMessage;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
@ -22,4 +24,14 @@ public interface ChatMessageRepository extends JpaRepository<ChatMessage, Long>
+ "(m.fromUser.userName = ?1 or m.fromUser.userName = ?2) and"
+ "(m.messageTime > ?3) order by m.messageTime asc")
public List<ChatMessage> getNewMessages(String fromUser, String toUser, Date lastMessageTime);
@Query("select m from ChatMessage m where (m.toUser.userName = ?1 or m.toUser.userName = ?2) and "
+ "(m.fromUser.userName = ?1 or m.fromUser.userName = ?2) order by m.messageTime asc")
public List<ChatMessage> getAllMessages(String fromUser, String toUser, PageRequest pageRequest);
// DELETE FROM Country c WHERE c.population < :p
// @Query("delete from ChatMessage m where where (m.toUser.userName = ?1 or m.toUser.userName = ?2) and"
// + " (m.fromUser.userName = ?1 or m.fromUser.userName = ?2)")
// public void deleteConversation(String fromUser, String toUser);
}

3
chatto/src/main/java/org/ros/chatto/repository/UserRoleRepository.java

@ -14,4 +14,7 @@ public interface UserRoleRepository extends JpaRepository<UserRole, Long>{
@Query("select ur from UserRole ur where ur.user.userName = ?1")
public List<UserRole> findByUser(String username);
@Query("select ur.user.userName from UserRole ur where ur.role.roleID = 2")
public List<String> getAllRegularUser();
}

25
chatto/src/main/java/org/ros/chatto/service/ChatService.java

@ -4,14 +4,23 @@ import java.util.Date;
import java.util.List;
import org.ros.chatto.dto.ChatMessageDTO;
import org.ros.chatto.model.MessageCipher;
import org.ros.chatto.dto.MessageCipherDTO;
import org.ros.chatto.dto.ReencryptionDTO;
import org.ros.chatto.model.ChatMessage;
import org.springframework.data.domain.PageRequest;
public interface ChatService {
void saveNewMessage(String fromUser, String toUser , MessageCipher messageCipher);
List<ChatMessageDTO> getAllMessages(String fromUser, String toUser);
List<ChatMessageDTO> getMessagePage(int page, int size);
List<ChatMessageDTO> getNewMessages(String fromUser, String toUser, Date lastMessageTime);
public void saveNewMessage(String fromUser, String toUser, MessageCipherDTO messageCipherDTO);
public List<ChatMessageDTO> getAllMessages(String fromUser, String toUser);
public List<ChatMessageDTO> getMessagePage(String fromUser, String toUser, int page, int size);
public List<ChatMessageDTO> getNewMessages(String fromUser, String toUser, Date lastMessageTime);
public void reencryptMessages(List<ReencryptionDTO> reencryptionDTOs);
public List<ReencryptionDTO> getAllMessagesForReencryption(String fromUser, String toUser);
public List<ChatMessageDTO> getAllMessages(String name, String userName, PageRequest pageRequest);
}

38
chatto/src/main/java/org/ros/chatto/service/ChatServiceImpl.java

@ -2,8 +2,13 @@ package org.ros.chatto.service;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.transaction.Transactional;
import org.ros.chatto.dto.ChatMessageDTO;
import org.ros.chatto.dto.MessageCipherDTO;
import org.ros.chatto.dto.ReencryptionDTO;
import org.ros.chatto.model.ChatMessage;
import org.ros.chatto.model.ChatUser;
import org.ros.chatto.model.MessageCipher;
@ -29,8 +34,9 @@ public class ChatServiceImpl implements ChatService {
@Autowired
MyConversionService myConversionService;
public void saveNewMessage(String fromUserName, String toUserName, MessageCipher messageCipher) {
public void saveNewMessage(String fromUserName, String toUserName, MessageCipherDTO messageCipherDTO) {
MessageCipher messageCipher = myConversionService.convertToMessageCipher(messageCipherDTO);
ChatUser fromUser = userRepository.findByUserName(fromUserName);
ChatUser toUser = userRepository.findByUserName(toUserName);
ChatMessage chatMessage = new ChatMessage();
@ -49,13 +55,19 @@ public class ChatServiceImpl implements ChatService {
List<ChatMessageDTO> chatMessageDTOs = myConversionService.convertToChatMessageDTOs(chatMessages);
return chatMessageDTOs;
}
@Override
public List<ReencryptionDTO> getAllMessagesForReencryption(String fromUser, String toUser) {
return myConversionService.convertToReencryptionDTOs(chatMessageRepository.getAllMessages(fromUser, toUser));
}
@Override
public List<ChatMessageDTO> getMessagePage(int page, int size) {
public List<ChatMessageDTO> getMessagePage(String fromUser, String toUser, int page, int size) {
// Sort sort = Sort
Page<ChatMessage> chatMessages = chatMessageRepository.findAll(PageRequest.of(page, size));
List<ChatMessageDTO> chatMessageDTOs = myConversionService.convertToChatMessageDTOs(chatMessages);
return chatMessageDTOs;
// Page<ChatMessage> chatMessages = chatMessageRepository.getAllMessages(fromUser, toUser,PageRequest.of(page, size));
// List<ChatMessageDTO> chatMessageDTOs = myConversionService.convertToChatMessageDTOs(chatMessages);
// return chatMessageDTOs;
return myConversionService.convertToChatMessageDTOs(chatMessageRepository.getAllMessages(fromUser, toUser,PageRequest.of(page, size)));
}
@Override
@ -65,4 +77,20 @@ public class ChatServiceImpl implements ChatService {
// List<ChatMessageDTO> chatMessageDTOs
return myConversionService.convertToChatMessageDTOs(chatMessages);
}
@Override
@Transactional
public void reencryptMessages(List<ReencryptionDTO> reencryptionDTOs) {
// TODO Auto-generated method stub
// chatMessageRepository.saveAll(chatMessages);
List<MessageCipher> messageCiphers = reencryptionDTOs.stream().map(reencryptionDTO -> reencryptionDTO.getMessageCipher()).collect(Collectors.toList());
messageCipherRepository.saveAll(messageCiphers);
}
@Override
public List<ChatMessageDTO> getAllMessages(String name, String userName, PageRequest pageRequest) {
// TODO Auto-generated method stub
return null;
}
}

60
chatto/src/main/java/org/ros/chatto/service/DBInitializerService.java

@ -2,7 +2,6 @@ package org.ros.chatto.service;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
@ -10,9 +9,15 @@ import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.ros.chatto.ChattoApplication;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.ros.chatto.model.ApplicationStatus;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.PropertySource;
@ -51,6 +56,12 @@ public class DBInitializerService {
private Connection connection;
@PersistenceContext
EntityManager entityManager;
private final String tablesCreatedKey = "tables_created";
private final String rolesPopulatedKey = "roles_populated";
// public DBInitializerService(Connection connection) {
// this.connection = connection;
// // TODO Auto-generated constructor stub
@ -125,9 +136,29 @@ public class DBInitializerService {
@EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() throws SQLException, IOException {
// setProperties();
System.out.println("Hello world, I have just started up");
System.out.println("Initializing database");
List<ApplicationStatus> applicationStatusList = getStatusList();
Map<String, Boolean> statusMap = listToMap(applicationStatusList);
// applicationStatus.
connectDB();
/*
* if (statusMap.get(tablesCreatedKey) == null ||
* !statusMap.get(tablesCreatedKey)) {
* System.out.println("Initializing database"); if (getNumTables() == 0) {
* populateDB(); System.out.println("Tables created"); } ApplicationStatus
* status = new ApplicationStatus(); status.setName(tablesCreatedKey);
* status.setDone(true);
*
* }
*
* if (statusMap.get(rolesPopulatedKey) == null ||
* !statusMap.get(rolesPopulatedKey)) { System.out.println("Populating roles");
* }
*/
if (getNumTables() == 0)
populateDB();
closeConnection();
@ -163,7 +194,7 @@ public class DBInitializerService {
public void setProperties() throws IOException {
// InputStream input = ChattoApplication.class.getClassLoader().getResourceAsStream("messages.properties");
OutputStream outputStream = new FileOutputStream("messages.properties");
OutputStream outputStream = new FileOutputStream("messages.properties");
// FileInputStream in = new FileInputStream("First.properties");
// Properties props = new Properties();
// props.load(in);
@ -175,14 +206,14 @@ public class DBInitializerService {
// out.close();
Properties prop = new Properties();
System.out.println("Hello from setProperties");
prop.setProperty("test.bindAddress", bindAddress);
prop.store(outputStream, null);
// if (input == null) {
// System.out.println("Sorry, unable to find messages.properties");
// return;
// }
// load a properties file from class path, inside static method
// prop.load(input);
// Object object = prop.setProperty("test.bindAddress", bindAddress);
@ -191,6 +222,23 @@ public class DBInitializerService {
// prop.store(object, comments);
}
List<ApplicationStatus> getStatusList() {
// List<Object[]> persons = entityManager.createNativeQuery("SELECT * FROM Person" ).getResultList();
List<ApplicationStatus> applicationStatus = entityManager
.createQuery("from ApplicationStatus s", ApplicationStatus.class).getResultList();
applicationStatus.stream().forEach(status -> status.getName());
// System.out.println(applicationStatus.get(0).getName() + applicationStatus.get(0).isDone());
return applicationStatus;
}
Map<String, Boolean> listToMap(List<ApplicationStatus> applicationStatusList) {
Map<String, Boolean> statusMap = new HashMap<>();
for (ApplicationStatus applicationStatus : applicationStatusList) {
statusMap.put(applicationStatus.getName(), applicationStatus.isDone());
}
return statusMap;
}
public void closeConnection() throws SQLException {
connection.close();
}

42
chatto/src/main/java/org/ros/chatto/service/MyConversionService.java

@ -5,7 +5,10 @@ import java.util.stream.Collectors;
import org.modelmapper.ModelMapper;
import org.ros.chatto.dto.ChatMessageDTO;
import org.ros.chatto.dto.MessageCipherDTO;
import org.ros.chatto.dto.ReencryptionDTO;
import org.ros.chatto.model.ChatMessage;
import org.ros.chatto.model.MessageCipher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
@ -42,6 +45,18 @@ public class MyConversionService {
return chatMessageDTO;
}
public ChatMessage convertToChatMessage(ChatMessageDTO chatMessageDTO)
{
ChatMessage chatMessage = modelMapper.map(chatMessageDTO, ChatMessage.class);
return chatMessage;
}
public MessageCipher convertToMessageCipher(MessageCipherDTO messageCipherDTO)
{
MessageCipher messageCipher = modelMapper.map(messageCipherDTO, MessageCipher.class);
return messageCipher;
}
public List<ChatMessageDTO> convertToChatMessageDTOs(List<ChatMessage> chatMessages)
{
return chatMessages.stream()
@ -49,6 +64,33 @@ public class MyConversionService {
.collect(Collectors.toList());
}
public ReencryptionDTO convertToReencryptionDTO(ChatMessage chatMessage)
{
ReencryptionDTO reencryptionDTO = modelMapper.map(chatMessage, ReencryptionDTO.class);
return reencryptionDTO;
}
public ChatMessage convertToChatMessage(ReencryptionDTO reencryptionDTO)
{
ChatMessage chatMessage = modelMapper.map(reencryptionDTO, ChatMessage.class);
return chatMessage;
}
public List<ReencryptionDTO> convertToReencryptionDTOs(List<ChatMessage> chatMessages)
{
return chatMessages.stream()
.map(chatMessage -> convertToReencryptionDTO(chatMessage))
.collect(Collectors.toList());
}
public Iterable<ChatMessage> convertoToChatMessages(List<ChatMessageDTO> chatMessageDTOs)
{
return chatMessageDTOs.stream()
.map(chatMessageDTO -> convertToChatMessage(chatMessageDTO)).collect(Collectors.toList());
}
public List<ChatMessageDTO> convertToChatMessageDTOs(Page<ChatMessage> chatMessages)
{
return chatMessages.stream()

1
chatto/src/main/java/org/ros/chatto/service/UserService.java

@ -11,4 +11,5 @@ public interface UserService {
public void saveChatUser(ChatUser user);
public List<String> findAllOtherUsers(String userName);
public void registerUser(UserRegistrationDTO userRegistrationDTO);
public List<String> getAllRegularUsers();
}

6
chatto/src/main/java/org/ros/chatto/service/UserServiceImpl.java

@ -62,4 +62,10 @@ public class UserServiceImpl implements UserService{
return userRepositoryCustom.getAllUserNames(userName);
}
@Override
public List<String> getAllRegularUsers() {
// TODO Auto-generated method stub
return userRoleRepository.getAllRegularUser();
}
}

3
chatto/src/main/resources/queries.properties

@ -1 +1,2 @@
num-tables = SELECT COUNT(*) as num_tables FROM information_schema.tables WHERE table_schema = ? and TABLE_TYPE='BASE TABLE'
num-tables = SELECT COUNT(*) as num_tables FROM information_schema.tables WHERE table_schema = ? and TABLE_TYPE='BASE TABLE'
#tables-created =

135
chatto/src/main/resources/static/js/admin.js

@ -0,0 +1,135 @@
console.log('Hello world!');
var getAllMessagesURL = `http://${hostAddress}/api/admin/get/messages/`; //hostAddress set in thymeleaf backend
var reencryptURL = `http://${hostAddress}/api/admin/post/re-encrypt`;
var getAllRegularUsersURL = `http://${hostAddress}/api/regular-users`;
var username = sessionStorage.getItem('username');
var password = sessionStorage.getItem('password');
var authToken = 'Basic ' + btoa(username + ":" + password);
var iterations = 10000;
function handleAddToAdminForm() {
document.getElementById('addUserToAdminForm').addEventListener(
'submit',
function(e) {
e.preventDefault();
getAllRegularUsers()
// .then(usernamesArray => {
// console.lo
// });
});
}
function handleChangePassphraseForm() {
document.getElementById('changePassphraseForm').addEventListener(
'submit',
function(e) {
e.preventDefault();
let changePassphraseDropDown = document.getElementById('changePassphraseDropDown');
let user = changePassphraseDropDown.value;
let passphraseOld = document.getElementById('passphraseOld');
let passphraseNew = document.getElementById('passphraseNew');
// let messageCipherNew = {};
console.log(user);
getAllMessages(user)
.then(json => {
console.log(json);
return json;
})
.then(json => {
let jsonNew = [];
let messageCiphers = [];
let chatMessageDTOs = [];
if (json.length > 0) {
json.forEach(function(obj) {
let newObj = obj;
let messageID = obj.messageCipher.id;
let plainText = sjcl.decrypt(passphraseOld.value, JSON.stringify(obj.messageCipher));
let messageCipherNew = sjcl.encrypt(passphraseNew.value, plainText, { mode: "gcm", ts: 128, adata: "", iter: iterations });
// let plainText = sjcl.decrypt("password", JSON.stringify(obj.messageCipher));
// let messageCipherNew = sjcl.encrypt("password2", plainText, { mode: "gcm", ts: 128, adata: "", iter: iterations });
// console.log(messageCipherNew)
let messageCipherNewObj = JSON.parse(messageCipherNew);
// console.log(messageCipherNewObj);
messageCipherNewObj.id = messageID;
newObj.messageCipher = messageCipherNewObj;
// obj.messageCipher = messageCipherNewObj;
// console.log(obj.messageCipher);
// console.log(plainText);
// console.log(messageCipherNewObj);
jsonNew.push(newObj);
messageCiphers.push(messageCipherNewObj);
// let messageCipherJson = JSON.stringify(messageCipherNewObj);
let fromUser = sessionStorage.getItem('username');
let chatMessageDTO = {
"toUser": user,
"fromUser": username,
"messageCipher": messageCipherNewObj
}
chatMessageDTOs.push(chatMessageDTO);
});
// console.log(jsonNew);
}
// sendReencryptedMessages(JSON.stringify(jsonNew));
console.log
sendReencryptedMessages(JSON.stringify(chatMessageDTOs));
// sendReencryptedMessages(JSON.stringify(messageCiphers));
return jsonNew;
})
.then(json => {
json.forEach(function(obj) {
let plainText = sjcl.decrypt("password2", JSON.stringify(obj.messageCipher));
console.log(plainText);
})
});
});
}
async function getAllMessages(user) {
let headers = new Headers();
// headers.append('Accept','application/json')
// headers.append('Content-Type', 'application/json');
headers.append('Authorization', authToken);
let response = await fetch(`${getAllMessagesURL}${user}`, {
method: 'GET',
headers: headers
});
let data = await response.json();
return data;
}
async function getAllRegularUsers() {
let headers = new Headers();
// headers.append('Accept','application/json')
// headers.append('Content-Type', 'application/json');
headers.append('Authorization', authToken);
let response = await fetch(`${getAllRegularUsersURL}`, {
method: 'GET',
headers: headers
});
let data = await response.json();
return data;
}
function sendReencryptedMessages(chatMessageDTOs) {
let headers = new Headers();
// console.log("Token = " + btoa("hmm" + ":" + "hmm"))
// headers.append('Accept','application/json')
headers.append('Content-Type', 'application/json');
headers.append('Authorization', authToken);
fetch(reencryptURL, {
method: 'POST',
headers: headers,
body: chatMessageDTOs
})
.then(response => console.log(response));
}
handleAddToAdminForm();
handleChangePassphraseForm();

396
chatto/src/main/resources/static/js/chat.js

@ -37,68 +37,78 @@ var iterations = 100000;
// var user;
function getSelectedUser() {
for (var i = 0; i < toUserRadios.length; i++) {
if (toUserRadios[i].checked) {
let user = toUserRadios[i].value;
console.log('sending to user = ' + user);
isCheckedUser = true;
return user;
}
}
for (var i = 0; i < toUserRadios.length; i++) {
if (toUserRadios[i].checked) {
let user = toUserRadios[i].value;
console.log('sending to user = ' + user);
isCheckedUser = true;
return user;
}
}
}
// console.log('Credentials = ' + JSON.parse(sessionStorage.getItem('credentials')));
function handleChatForm() {
let chatInput = document.getElementById('chatInput');
let myForm = document.getElementById('chatMessageForm').addEventListener(
'submit', function (e) {
e.preventDefault();
let user = getSelectedUser();
if (!isCheckedUser) {
window.alert('please select a user');
return;
}
// console.log('second user = ' + user);
let messageContent = chatInput.value;
let localDate = new Date();
let messageLine = sprintf('%s %s %s: %s', localDate.toLocaleDateString(), localDate.toLocaleTimeString(), username, messageContent);
chatTextArea.append(messageLine + "\n");
chatTextArea.scrollTop = chatTextArea.scrollHeight;
// let messageCipher = sjcl.encrypt("password", messageContent);
let messageCipher = sjcl.encrypt(passphraseInput.value, messageContent,{mode: "gcm",ts: 128, adata: "",iter: iterations});
let messageCipherJson = JSON.parse(messageCipher);
// let messageCipherSpring = JSON.stringify(messageCipherJson);
// console.log('message cipher json ' + messageCipherJson);
// console.log('message cipher string ' + messageCipherSpring);
let chatMessageDTO = {
"toUser": user,
"messageCipher": messageCipherJson
}
// console.log(chatMessageDTO);
// console.log(JSON.stringify(chatMessageDTO));
messageSend(JSON.stringify(chatMessageDTO));
// sessionStorage.setItem('passphrase', passphraseInput.value);
// console.log(sessionStorage.getItem('passphrase'));
})
let chatInput = document.getElementById('chatInput');
let myForm = document.getElementById('chatMessageForm');
myForm.addEventListener(
'submit',
function(e) {
e.preventDefault();
let user = getSelectedUser();
if (!myForm.checkValidity()) {
console.log("error");
myForm.classList.add('was-validated');
return;
}
myForm.classList.add('was-validated');
if (!isCheckedUser) {
window.alert('please select a user');
return;
}
// console.log('second user = ' + user);
let messageContent = chatInput.value;
let localDate = new Date();
let messageLine = sprintf('%s %s %s: %s', localDate.toLocaleDateString(), localDate.toLocaleTimeString(), username, messageContent);
chatTextArea.append(messageLine + "\n");
chatTextArea.scrollTop = chatTextArea.scrollHeight;
// let messageCipher = sjcl.encrypt("password", messageContent);
let messageCipher = sjcl.encrypt(passphraseInput.value, messageContent, { mode: "gcm", ts: 128, adata: "", iter: iterations });
let messageCipherJson = JSON.parse(messageCipher);
// let messageCipherSpring = JSON.stringify(messageCipherJson);
// console.log('message cipher json ' + messageCipherJson);
// console.log('message cipher string ' + messageCipherSpring);
let chatMessageDTO = {
"toUser": user,
"messageCipher": messageCipherJson
}
// console.log(chatMessageDTO);
// console.log(JSON.stringify(chatMessageDTO));
messageSend(JSON.stringify(chatMessageDTO));
// sessionStorage.setItem('passphrase', passphraseInput.value);
// console.log(sessionStorage.getItem('passphrase'));
})
}
function messageSend(chatMessageDTO) {
let headers = new Headers();
// console.log("Token = " + btoa("hmm" + ":" + "hmm"))
// headers.append('Accept','application/json')
headers.append('Content-Type', 'application/json');
headers.append('Authorization', authToken);
fetch(postNewMessageUrl, {
method: 'POST',
headers: headers,
body: chatMessageDTO
})
.then(response => console.log(response));
let headers = new Headers();
// console.log("Token = " + btoa("hmm" + ":" + "hmm"))
// headers.append('Accept','application/json')
headers.append('Content-Type', 'application/json');
headers.append('Authorization', authToken);
fetch(postNewMessageUrl, {
method: 'POST',
headers: headers,
body: chatMessageDTO
})
.then(response => console.log(response));
}
// function getMessages(toUser) {
@ -151,155 +161,153 @@ function messageSend(chatMessageDTO) {
// .then(data => console.log(data));
async function getAllMessages(toUser) {
let headers = new Headers();
// headers.append('Accept','application/json')
// headers.append('Content-Type', 'application/json');
headers.append('Authorization', authToken);
let response = await fetch(getAllMessagesUrl + toUser, {
method: 'GET',
headers: headers
});
let data = await response.json();
return data;
let headers = new Headers();
// headers.append('Accept','application/json')
// headers.append('Content-Type', 'application/json');
headers.append('Authorization', authToken);
let response = await fetch(getAllMessagesUrl + toUser, {
method: 'GET',
headers: headers
});
let data = await response.json();
return data;
}
async function getNewMessages(toUser, lastMessageTimeStamp) {
let headers = new Headers();
headers.append('Authorization', authToken);
let response = await fetch(`${getNewMessagesUrl}${toUser}/${lastMessageTimeStamp}`, {
method: 'GET',
headers: headers
});
let data = await response.json();
return data;
let headers = new Headers();
headers.append('Authorization', authToken);
let response = await fetch(`${getNewMessagesUrl}${toUser}/${lastMessageTimeStamp}`, {
method: 'GET',
headers: headers
});
let data = await response.json();
return data;
}
// getMessages('user2');
window.EventTarget.prototype.addDelegatedListener = function (type, delegateSelector, listener) {
this.addEventListener(type, function (event) {
if (event.target && event.target.matches(delegateSelector)) {
listener.call(event.target, event)
}
});
window.EventTarget.prototype.addDelegatedListener = function(type, delegateSelector, listener) {
this.addEventListener(type, function(event) {
if (event.target && event.target.matches(delegateSelector)) {
listener.call(event.target, event)
}
});
}
let parent = document.getElementById('chatMessageForm')
parent.addDelegatedListener("click", "input[type='radio']", function (event) {
// if (sessionStorage.getItem('status') != null) {
if (passphraseInput.value == '') {
alert('Please input passphrase')
return;
}
console.log(this.value);
if (sessionStorage.getItem(this.value) == null) {
chatTextArea.textContent = '';
getAllMessages(this.value)
.then(json => {
console.log(json);
let i = 0;
let messageLog = [];
let lastMessageTimeStamp;
// console.log("Json length = " + json.length);
//
// if(json.length == 0)
// {
// console.log("JSON LENGTH IS 0")
// }
if (json.length > 0) {
json.forEach(function (obj) {
// console.log(obj.toUser);
messageCipher = JSON.stringify(obj.messageCipher);
console.log(messageCipher);
// let message = sjcl.decrypt("password", messageCipher);
let message = sjcl.decrypt(passphraseInput.value, messageCipher);
let utcDate = obj.messageTime;
lastMessageTimeStamp = utcDate;
let localDate = new Date(utcDate);
let messageLine = sprintf('%s %s: %s ', localDate, obj.fromUser, message);
// localDate.``
// console.log('localDate = ' + localDate);
console.log(messageLine);
// chatTextArea.append(obj.fromUser + ": " + message + "\n");
chatTextArea.append(messageLine + '\n');
messageLog[i++] = messageLine;
chatTextArea.scrollTop = chatTextArea.scrollHeight;
// console.log('Message log = ' + messageLog);
});
sessionStorage.setItem(this.value, JSON.stringify(messageLog));
// sessionStorage.clear();
console.log('Last message time = ' + lastMessageTimeStamp);
sessionStorage.setItem(this.value + '-time', lastMessageTimeStamp);
}
});
}
else {
console.log("Stored messages = " + sessionStorage.getItem(this.value));
let storedMessages = JSON.parse(sessionStorage.getItem(this.value));
let lastMessageTime = sessionStorage.getItem(this.value + '-time');
console.log("last message time stamp = " + lastMessageTime);
if (lastMessageTime != null) {
getNewMessages(this.value, lastMessageTime)
.then(json => {
console.log(json)
if (json.length > 0) {
json.forEach(function (obj) {
let messageCipher = JSON.stringify(obj.messageCipher);
let message = sjcl.decrypt(passphraseInput.value, messageCipher);
// console.log(message);
// chatTextArea.append(message + "\n");
let utcDate = obj.messageTime;
lastMessageTimeStamp = utcDate;
let localDate = new Date(utcDate);
let messageLine = sprintf('%s %s: %s', localDate, obj.fromUser, message);
// localDate.``
// console.log('localDate = ' + localDate);
console.log(messageLine);
// chatTextArea.append(obj.fromUser + ": " + message + "\n");
chatTextArea.append(messageLine + '\n');
chatTextArea.scrollTop = chatTextArea.scrollHeight;
storedMessages.push(messageLine);
})
sessionStorage.setItem(this.value + '-time', lastMessageTimeStamp);
sessionStorage.setItem(this.value, JSON.stringify(storedMessages));
console.log("this value stored" + sessionStorage.getItem(this.value))
console.log("last message time stamp = " + lastMessageTimeStamp);
console.log(sessionStorage.getItem(this.value + '-time'));
}
chatTextArea.textContent = '';
console.log("Stored messages 2 = " + storedMessages);
storedMessages.forEach(function (messageLine) {
chatTextArea.append(messageLine + '\n');
chatTextArea.scrollTop = chatTextArea.scrollHeight;
})
});
}
// sessionStorage.clear();
// chatTextArea.append(JSON.stringify(storedMessages));
}
// sessionStorage.setItem('status', 'ready');
// sessionStorage.setItem('this.value', messageLog);
// console.log('Message log = ' + messageLog);
// }
// let passphraseKey = this.value + '-passphrase';
// sessionStorage.setItem(passphraseKey, passphraseInput.value);
// console.log(sessionStorage.getItem(passphraseKey));
});
parent.addDelegatedListener("click", "input[type='radio']", function(event) {
// if (sessionStorage.getItem('status') != null) {
if (passphraseInput.value == '') {
alert('Please input passphrase')
return;
}
console.log(this.value);
if (sessionStorage.getItem(this.value) == null) {
chatTextArea.textContent = '';
getAllMessages(this.value)
.then(json => {
console.log(json);
let i = 0;
let messageLog = [];
let lastMessageTimeStamp;
// console.log("Json length = " + json.length);
//
// if(json.length == 0)
// {
// console.log("JSON LENGTH IS 0")
// }
if (json.length > 0) {
json.forEach(function(obj) {
// console.log(obj.toUser);
messageCipher = JSON.stringify(obj.messageCipher);
console.log(messageCipher);
// let message = sjcl.decrypt("password", messageCipher);
let message = sjcl.decrypt(passphraseInput.value, messageCipher);
let utcDate = obj.messageTime;
lastMessageTimeStamp = utcDate;
let localDate = new Date(utcDate);
let messageLine = sprintf('%s %s: %s ', localDate, obj.fromUser, message);
// localDate.``
// console.log('localDate = ' + localDate);
console.log(messageLine);
// chatTextArea.append(obj.fromUser + ": " + message + "\n");
chatTextArea.append(messageLine + '\n');
messageLog[i++] = messageLine;
chatTextArea.scrollTop = chatTextArea.scrollHeight;
// console.log('Message log = ' + messageLog);
});
sessionStorage.setItem(this.value, JSON.stringify(messageLog));
// sessionStorage.clear();
console.log('Last message time = ' + lastMessageTimeStamp);
sessionStorage.setItem(this.value + '-time', lastMessageTimeStamp);
}
});
} else {
console.log("Stored messages = " + sessionStorage.getItem(this.value));
let storedMessages = JSON.parse(sessionStorage.getItem(this.value));
let lastMessageTime = sessionStorage.getItem(this.value + '-time');
console.log("last message time stamp = " + lastMessageTime);
if (lastMessageTime != null) {
getNewMessages(this.value, lastMessageTime)
.then(json => {
console.log(json)
if (json.length > 0) {
json.forEach(function(obj) {
let messageCipher = JSON.stringify(obj.messageCipher);
let message = sjcl.decrypt(passphraseInput.value, messageCipher);
// console.log(message);
// chatTextArea.append(message + "\n");
let utcDate = obj.messageTime;
lastMessageTimeStamp = utcDate;
let localDate = new Date(utcDate);
let messageLine = sprintf('%s %s: %s', localDate, obj.fromUser, message);
// localDate.``
// console.log('localDate = ' + localDate);
console.log(messageLine);
// chatTextArea.append(obj.fromUser + ": " + message + "\n");
chatTextArea.append(messageLine + '\n');
chatTextArea.scrollTop = chatTextArea.scrollHeight;
storedMessages.push(messageLine);
})
sessionStorage.setItem(this.value + '-time', lastMessageTimeStamp);
sessionStorage.setItem(this.value, JSON.stringify(storedMessages));
console.log("this value stored" + sessionStorage.getItem(this.value))
console.log("last message time stamp = " + lastMessageTimeStamp);
console.log(sessionStorage.getItem(this.value + '-time'));
}
chatTextArea.textContent = '';
console.log("Stored messages 2 = " + storedMessages);
storedMessages.forEach(function(messageLine) {
chatTextArea.append(messageLine + '\n');
chatTextArea.scrollTop = chatTextArea.scrollHeight;
})
});
}
// sessionStorage.clear();
// chatTextArea.append(JSON.stringify(storedMessages));
}
// sessionStorage.setItem('status', 'ready');
// sessionStorage.setItem('this.value', messageLog);
// console.log('Message log = ' + messageLog);
// }
// let passphraseKey = this.value + '-passphrase';
// sessionStorage.setItem(passphraseKey, passphraseInput.value);
// console.log(sessionStorage.getItem(passphraseKey));
});
handleChatForm();
handleChatForm();

109
chatto/src/main/resources/templates/admin/home.html

@ -1,13 +1,110 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<div th:replace="fragments/head :: headFragment">
<title id="pageTitle">Admin Home</title>
</div>
<script src="https://code.jquery.com/jquery-2.1.4.min.js" th:if="false"></script>
<script src="http://blackpeppersoftware.github.io/thymeleaf-fragment.js/thymeleaf-fragment.js" data-template-prefix="../" defer="defer" th:if="false"></script>
<script th:src="@{js/admin.js}" src="../../static/js/admin.js" defer="defer"></script>
<link th:href="@{/css/master.css}" href="../../static/css/master.css" rel="stylesheet" th:if="false">
<link th:href="@{/css/colors.css}" href="../../static/css/colors.css" rel="stylesheet" th:if="false">
</head>
<!-- TODO
Make user admin / remove user from admin
Change E2E passphrase
Delete Messages
-->
<body>
admin page
<form action="#" th:action="@{/perform_logout}" method="POST">
<input type="submit" value="logout">
</form>
<div th:include="fragments/navbar :: navbarFragment"></div>
<header>
<div class="container bg-primary">
<div class="row">
<div class="col-sm py-5">
<h1 class="display-4 text-center">Admin Page</h1>
<p class="alert-danger px-2">Warning: these settings can be dangerous..</p>
</div>
</div>
<div class="row">
<div class="col-sm col-md-4">
<h4>Make User an Admin</h4>
<form id="addUserToAdminForm">
<div class="form-group">
<label for="addUserToDropDown">Select User:</label>
<select class="form-control custom-select" size="4" id="addUserToAdminDropDown">
<option th:each="userName : ${userNames}"
th:value="${userName}"
th:text="#{${userName}}">
Wireframe
</option>
</select>
</div>
<div class="form-group">
<button class="btn btn-danger form-control">Make admin</button>
</div>
</form>
</div>
<div class="col-sm col-md-4">
<h4>Change passphrases</h4>
<form id="changePassphraseForm">
<div class="form-group">
<label for="changePassphraseDropDown">Select User:</label>
<select class="form-control" id="changePassphraseDropDown">
<option th:each="userName : ${userNames}"
th:value="${userName}"
th:text="#{${userName}}">
Wireframe
</option>
</select>
</div>
<div class="form-group">
<label for="passphraseOld">Passphrase Old</label>
<input type="password" id="passphraseOld" class="form-control">
</div>
<div class="form-group">
<label for="passphraseNew">Passphrase New</label>
<input type="password" id="passphraseNew" class="form-control">
</div>
<div class="form-group">
<button class="btn btn-danger form-control">Change Passphrase</button>
</div>
</form>
</div>
</div>
<div class="row">
<!-- <div class="col-sm"></div> -->
<div class="col-sm d-lg-block">
<div class="d-flex justify-content-center">
<div class="py-5">
<h4 class="p-2 text-center">Logout</h4>
<form action="#" th:action="@{/logout}" method="POST">
<!-- <input type="submit" value="logout"> -->
<!-- <input type="hidden" th:name="${_csrf.parameterName}"
th:value="${_csrf.token}" /> -->
<div class="form-group">
<button class="btn btn-secondary form-control">Logout</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</header>
</body>
</html>

18
chatto/src/main/resources/templates/chat.html

@ -45,7 +45,7 @@
<div class="row">
<div class="col-sm">
<h4 class="display-4 text-center py-2">Chat</h4>
<div class="card text-white bg-primary mb-3 text-center card-form rounded mx-auto">
<div class="card text-white bg-primary mb-3 card-form rounded mx-auto">
<div class="card-body rounded">
<!-- <h4 class="card-title">Chat</h4> -->
@ -57,7 +57,7 @@
<div class="card-text">
</div>
<form action="#" th:object="${chatMessageDTO}" method="post" id="chatMessageForm">
<form action="#" th:object="${chatMessageDTO}" method="post" id="chatMessageForm" class="needs-validation" novalidate>
<div class="row">
<div class="col-3">
<div class="form-group">
@ -65,8 +65,8 @@
<th:block th:each="userName: ${userNames}">
<input class="form-control" type="radio" th:field="*{toUser}" th:value="${userName}">
<label class="btn btn-secondary" th:for="${#ids.prev('toUser')}" th:text="${userName}">
Demo User
</label>
Demo User
</label>
</th:block>
</div>
</div>
@ -74,14 +74,18 @@
<div class="my-form-inputs container">
<div class="form-group">
<label for="chatInput">Your message: </label>
<textarea class="form-control" type="text" id="chatInput"></textarea>
<textarea class="form-control" type="text" id="chatInput" required></textarea>
<div class="invalid-feedback">
Cannot be empty
</div>
</div>
<div class="form-group">
<label for="passphrase">Passphrase: </label>
<input class="form-control" type="password" id="passphrase">
<input class="form-control" type="password" id="passphrase" required>
</div>
<div class="form-group">
<input class="form-control btn btn-secondary" type="submit" value="Send">
<button class="btn btn-secondary">Submit</button>
</div>
</div>
</div>

20
chatto/src/main/resources/templates/fragments/navbar.html

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<div th:replace="fragments/head :: headFragment">
@ -34,13 +34,16 @@
<a href="home.html" th:href="@{/}" class="nav-link">Home</a>
</li>
<li class="nav-item">
<a href="user/home.html" th:href="@{/user}" class="nav-link">User Area</a>
<a href="user/home.html" sec:authorize="isFullyAuthenticated()" th:href="@{/user}" class="nav-link">User Area</a>
</li>
<li class="nav-item">
<a th:href="chat" href="chat.html" class="nav-link">Chat</a>
</li>
<li class="nav-item">
<a th:href="login" href="login.html" class="nav-link">Login</a>
<a th:href="login" sec:authorize="!isFullyAuthenticated()" href="login.html" class="nav-link">Login</a>
</li>
<li class="nav-item">
<a th:href="registration" sec:authorize="!isFullyAuthenticated()" href="registration.html" class="nav-link">Register</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">About</a>
@ -48,7 +51,16 @@
<li class="nav-item">
<a href="#" class="nav-link">Contact</a>
</li>
<li class="nav-item">
<a href="#" sec:authorize="isFullyAuthenticated()" th:href="@{/admin}" class="nav-link">
Admin Area
</a>
</li>
<li class="nav-item">
<a href="#" sec:authorize="isFullyAuthenticated()" th:text="${#authentication.name}" class="nav-link text-white font-weight-bold">
nova
</a>
</li>
</ul>
</div>
</div>

13
chatto/src/main/resources/templates/home.html

@ -1,5 +1,5 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<div th:replace="fragments/head :: headFragment">
@ -35,7 +35,7 @@
<th:block th:each="userName: ${userNames}">
<div th:text="${userName}"></div>
</th:block> -->
<span th:if="${message}"> Welcome <span th:text="${message}"></span></span>
<span th:if="${message}"> </span> Welcome <span th:text="${#authentication.name}">nova</span>
<p>Chatto is a minimal, end to end encrypted chat application.</p>
<!-- <button class="btn btn-secondary"> <a href="registration.html" th:href="{@/registration}">Get Started</a></button> -->
<a class="btn btn-secondary" href="registration.html" th:href="@{/registration}">Get Started</a>
@ -53,12 +53,14 @@
<li>
<p class="lead">
<!-- <i class="fas fa-check"></i> -->
Self Hosted</p>
Self Hosted
</p>
</li>
<li>
<p class="lead">
<!-- <i class="fas fa-check"></i> -->
End To End Encrypted Messaging</p>
End To End Encrypted Messaging
</p>
</li>
<li>
<p class="lead">
@ -68,7 +70,8 @@
<li>
<p class="lead">
<!-- <i class="fas fa-check"></i> -->
Built With Java And Spring</p>
Built With Java And Spring
</p>
</li>
</ul>
</p>

2
chatto/src/main/resources/templates/login.html

@ -55,7 +55,7 @@
<legend>Please Sign In</legend> -->
<h2 class="card-title">Please Sign In</h2>
<div th:if="${param.error}" class="alert alert-danger">
Invalid username or password.
Error signing in. Please check your username and password.
</div>
<div th:if="${param.logout}" class="alert alert-success">
You have been logged out.

77
chatto/src/main/resources/templates/registration.html

@ -1,18 +1,73 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<div th:replace="fragments/head :: headFragment">
<title id="pageTitle">Registration</title>
</div>
<script src="https://code.jquery.com/jquery-2.1.4.min.js" th:if="false"></script>
<script src="http://blackpeppersoftware.github.io/thymeleaf-fragment.js/thymeleaf-fragment.js" defer="defer" th:if="false"></script>
</head>
<body>
<form action="#" th:action="@{/perform_registration}"
th:object=${userDTO} method="POST">
<label>Enter user name: </label> <input th:field="*{userName}"
type="text" name="username" id="username"> <br> <br>
<label>Enter password: </label> <input th:field="*{password}"
type="password" name="password" id="password"> <br> <br>
<input type="password" id="password-repeat">
<input type="submit" value="Submit">
</form>
<div th:include="fragments/navbar :: navbarFragment"></div>
<header>
<div class="container">
<div class="row">
<div class="col-sm py-5">
<!-- <h4 class="display-4 text-center py-2">Chat</h4> -->
<div class="card text-white bg-primary mb-3 text-center card-form rounded mx-auto" id="login-card">
<div class="card-body rounded">
<!-- <h4 class="card-title">Chat</h4> -->
<!-- <div class="form-group">
<textarea id="chatTextArea" class="form-control-lg py-2" disabled></textarea>
</div> -->
<!-- <form action="#" th:action="@{/seedstartermng}" th:object="${seedStarter}" method="post"> -->
<!-- th:action="@{/api/chat}" -->
<!-- <label>First Name</label>
<div th:classappend="${#fields.hasErrors('firstName')} ? 'input-icon right' : ''">
<i th:if="${#fields.hasErrors('firstName')}" class="fa fa-exclamation tooltips" data-original-title="please enter a valid first name" data-container="body"></i>
<input type="text" class="form-control" maxlength="32" th:field="*{firstName}" placeholder="Between 1 and 32 characters" />
<span th:if="${#fields.hasErrors('firstName')}" class="help-block" th:errors="*{firstName}"></span>
</div> -->
<div class="card-text">
<h2 class="card-title">Register</h2>
<form action="#" th:action="@{/perform_registration}" th:object=${userRegistrationDTO} method="POST">
<div class="form-group">
<label>Enter username: </label>
<div th:classappend="${#fields.hasErrors('userName')} ? 'input-icon right' : ''">
<i th:if="${#fields.hasErrors('userName')}" class="fa fa-exclamation tooltips" data-original-title="please enter a valid username" data-container="body"></i>
<input class="form-control" th:field="*{userName}" type="text" name="username" id="username" required>
<span th:if="${#fields.hasErrors('userName')}" class="help-block" th:errors="*{userName}"></span>
</div>
</div>
<div class="form-group">
<label>Enter password: </label>
<i th:if="${#fields.hasErrors('password')}" class="fa fa-exclamation tooltips" data-original-title="please enter a valid first name" data-container="body"></i>
<input class="form-control" th:field="*{password}" type="password" name="password" id="password" required>
<span th:if="${#fields.hasErrors('password')}" class="help-block" th:errors="*{password}"></span>
</div>
<div class="form-group">
<label for="password-repeat">Repeat password: </label>
<input class="form-control" type="password" id="password-repeat" required>
</div>
<div class="form-group">
<input class="form-control btn btn-secondary" type="submit" value="Submit">
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
</body>
</html>
Loading…
Cancel
Save