Browse Source

Implemented primitive rest validation.

A better implementation to be done later.
master
Rohan Sircar 5 years ago
parent
commit
d3ac95e8f4
  1. 4
      chatto/src/main/java/org/ros/chatto/controller/AdminRESTController.java
  2. 56
      chatto/src/main/java/org/ros/chatto/controller/ChatMessageController.java
  3. 5
      chatto/src/main/java/org/ros/chatto/controller/RegistrationController.java
  4. 12
      chatto/src/main/java/org/ros/chatto/dto/ChatMessageDTO.java
  5. 27
      chatto/src/main/java/org/ros/chatto/dto/MessageCipherDTO.java
  6. 9
      chatto/src/main/java/org/ros/chatto/dto/ReencryptionDTO.java
  7. 8
      chatto/src/main/java/org/ros/chatto/dto/UserRegistrationDTO.java
  8. 16
      chatto/src/main/java/org/ros/chatto/error/ErrorModel.java
  9. 17
      chatto/src/main/java/org/ros/chatto/error/ErrorResponse.java
  10. 6
      chatto/src/main/java/org/ros/chatto/model/ChatUser.java
  11. 4
      chatto/src/main/java/org/ros/chatto/service/ChatService.java
  12. 13
      chatto/src/main/java/org/ros/chatto/service/ChatServiceImpl.java
  13. 4
      chatto/src/main/java/org/ros/chatto/service/UserServiceImpl.java
  14. 1
      chatto/src/main/resources/static/js/admin.js
  15. 4
      chatto/src/main/resources/templates/fragments/head.html
  16. 19
      chatto/src/main/resources/templates/registration.html

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

@ -7,6 +7,8 @@ import java.time.format.DateTimeFormatterBuilder;
import java.util.Date;
import java.util.List;
import javax.validation.Valid;
import org.ros.chatto.dto.ChatMessageDTO;
import org.ros.chatto.dto.ReencryptionDTO;
import org.ros.chatto.model.ChatMessage;
@ -34,7 +36,7 @@ public class AdminRESTController {
@PostMapping(value = "/post/re-encrypt", consumes = { "application/json" })
@ResponseBody
public ResponseEntity<ReencryptionDTO> reencryptMessages(@RequestBody List<ReencryptionDTO> reencryptionDTOs,
public ResponseEntity<ReencryptionDTO> reencryptMessages(@RequestBody @Valid List<ReencryptionDTO> reencryptionDTOs,
Principal principal) {
if (reencryptionDTOs.size() > 0) {
chatService.reencryptMessages(reencryptionDTOs);

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

@ -6,16 +6,23 @@ import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.Valid;
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.error.ErrorModel;
import org.ros.chatto.error.ErrorResponse;
import org.ros.chatto.service.ChatService;
import org.ros.chatto.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@ -23,6 +30,7 @@ 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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@RestController
@ -36,14 +44,52 @@ public class ChatMessageController {
@PostMapping(value = "/post/message", consumes = { "application/json" })
@ResponseBody
public ResponseEntity<ChatMessageDTO> newMessage(@RequestBody ChatMessageDTO chatMessageDTO, Principal principal) {
public ResponseEntity<?> newMessage(@RequestBody @Valid ChatMessageDTO chatMessageDTO,
Principal principal) {
// if (bindingResult.hasErrors()) {
//
//// return new ResponseEntity<List<FieldError>>(bindingResult.getFieldErrors(),HttpStatus.BAD_REQUEST);
// return new ResponseEntity<ErrorResponse>(handleException(bindingResult), HttpStatus.BAD_REQUEST);
// }
MessageCipherDTO messageCipher = chatMessageDTO.getMessageCipher();
String fromUser = principal.getName();
String toUser = chatMessageDTO.getToUser();
System.out.println("Message cipher = " + messageCipher);
chatService.saveNewMessage(fromUser, toUser, messageCipher);
return new ResponseEntity<ChatMessageDTO>(HttpStatus.OK);
chatMessageDTO = chatService.saveNewMessage(fromUser, toUser, messageCipher);
HttpHeaders responseHeader = new HttpHeaders();
return new ResponseEntity<ChatMessageDTO>(chatMessageDTO, responseHeader, HttpStatus.CREATED);
}
/**
* Method that check against {@code @Valid} Objects passed to controller endpoints
*
* @param exception
* @return a {@code ErrorResponse}
* @see com.aroussi.util.validation.ErrorResponse
*/
@ExceptionHandler(value=MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleException(MethodArgumentNotValidException exception) {
List<ErrorModel> errorMessages = exception.getBindingResult().getFieldErrors().stream()
.map(err -> new ErrorModel(err.getField(), err.getRejectedValue(), err.getDefaultMessage()))
.distinct()
.collect(Collectors.toList());
return ErrorResponse.builder().errorMessage(errorMessages).build();
}
@ExceptionHandler(value=MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleException(BindingResult bindingResult) {
List<ErrorModel> errorMessages = bindingResult.getFieldErrors().stream()
.map(err -> new ErrorModel(err.getField(), err.getRejectedValue(), err.getDefaultMessage()))
.distinct()
.collect(Collectors.toList());
return ErrorResponse.builder().errorMessage(errorMessages).build();
}
@GetMapping(value = "/get/messages/{userName}")
@ResponseBody

5
chatto/src/main/java/org/ros/chatto/controller/RegisterController.java → chatto/src/main/java/org/ros/chatto/controller/RegistrationController.java

@ -25,8 +25,9 @@ public class RegistrationController {
}
@PostMapping("/perform_registration")
public String performRegistration(Model model,
@ModelAttribute("userRegistrationDTO") @Valid UserRegistrationDTO userRegistrationDTO, BindingResult bindingResult) {
public String performRegistration(
@ModelAttribute("userRegistrationDTO") @Valid UserRegistrationDTO userRegistrationDTO,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
System.out.println("Input has errors!");
return "registration";

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

@ -2,13 +2,21 @@ package org.ros.chatto.dto;
import java.util.Date;
import org.ros.chatto.model.MessageCipher;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import lombok.Data;
@Data
public class ChatMessageDTO {
private String toUser, fromUser;
@NotBlank(message = "Username should not be blank")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "Username must be alphanumeric")
@Size(max=15)
private String toUser;
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "Username must be alphanumeric")
@Size(max=15)
private String fromUser;
private MessageCipherDTO messageCipher;
private Date messageTime;
}

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

@ -1,5 +1,11 @@
package org.ros.chatto.dto;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
@ -8,18 +14,39 @@ import lombok.Setter;
@Getter
@Setter
public class MessageCipherDTO {
@Pattern(regexp = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$") // regex for base64
@NotBlank
private String iv;
@Max(1)
@NotBlank
private int v;
@Max(1_000_000)
@Min(1_000)
@NotBlank
@JsonProperty("iter")
private int iterations;
@Max(256)
@Min(128)
@JsonProperty("ks")
private int keySize;
@Max(256)
@Min(128)
@JsonProperty("ts")
private int tagSize;
@Pattern(regexp = "^[A-Za-z0-9]+$") // alphabetic
@NotBlank
private String mode;
@Pattern(regexp = "^[A-Za-z0-9]+$")
private String adata;
@Pattern(regexp = "^[A-Za-z0-9]+$")
@NotBlank
private String cipher;
@Pattern(regexp = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")
@NotBlank
private String salt;
@JsonProperty("ct")
@Pattern(regexp = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")
@NotBlank
@Size(max = 2000, min = 1)
private String cipherText;
}

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

@ -2,13 +2,22 @@ package org.ros.chatto.dto;
import java.util.Date;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.ros.chatto.model.MessageCipher;
import lombok.Data;
@Data
public class ReencryptionDTO {
@NotBlank(message = "Username should not be blank")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "Username must be alphanumeric")
@Size(max=15)
private String toUser, fromUser;
@NotBlank
@Size(max=600)
private MessageCipher messageCipher;
private Date messageTime;
}

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

@ -7,13 +7,13 @@ 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")
@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")
@Size(min = 4, max = 75, message = "Password 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() {

16
chatto/src/main/java/org/ros/chatto/error/ErrorModel.java

@ -0,0 +1,16 @@
package org.ros.chatto.error;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ErrorModel{
private String fieldName;
private Object rejectedValue;
private String messageError;
}

17
chatto/src/main/java/org/ros/chatto/error/ErrorResponse.java

@ -0,0 +1,17 @@
package org.ros.chatto.error;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ErrorResponse {
private List<ErrorModel> errorMessage;
}

6
chatto/src/main/java/org/ros/chatto/model/ChatUser.java

@ -28,12 +28,12 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@Entity
@Table(name = "users")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = { "password"}, allowGetters = false)
@JsonIgnoreProperties(value = { "password" }, allowGetters = false)
public class ChatUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
// @SequenceGenerator(name="user_generator", sequenceName = "user_seq", allocationSize=50)
// @SequenceGenerator(name="user_generator", sequenceName = "user_seq", allocationSize=50) //mysql does not support sequence id generator
@Column(name = "user_id")
private int userID;
@Column(name = "name")
@ -47,7 +47,7 @@ public class ChatUser {
@JsonBackReference
// private Set<UserRole> userRoles = new HashSet<UserRole>();
private Set<UserRole> userRoles;
public int getUserID() {
return userID;
}

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

@ -3,6 +3,8 @@ package org.ros.chatto.service;
import java.util.Date;
import java.util.List;
import javax.validation.Valid;
import org.ros.chatto.dto.ChatMessageDTO;
import org.ros.chatto.dto.MessageCipherDTO;
import org.ros.chatto.dto.ReencryptionDTO;
@ -10,7 +12,7 @@ import org.ros.chatto.model.ChatMessage;
import org.springframework.data.domain.PageRequest;
public interface ChatService {
public void saveNewMessage(String fromUser, String toUser, MessageCipherDTO messageCipherDTO);
public @Valid ChatMessageDTO saveNewMessage(String fromUser, String toUser, MessageCipherDTO messageCipherDTO);
public List<ChatMessageDTO> getAllMessages(String fromUser, String toUser);

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

@ -1,5 +1,6 @@
package org.ros.chatto.service;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@ -34,18 +35,26 @@ public class ChatServiceImpl implements ChatService {
@Autowired
MyConversionService myConversionService;
public void saveNewMessage(String fromUserName, String toUserName, MessageCipherDTO messageCipherDTO) {
@Transactional
public ChatMessageDTO saveNewMessage(String fromUserName, String toUserName, MessageCipherDTO messageCipherDTO) {
MessageCipher messageCipher = myConversionService.convertToMessageCipher(messageCipherDTO);
ChatUser fromUser = userRepository.findByUserName(fromUserName);
ChatUser toUser = userRepository.findByUserName(toUserName);
// if(fromUser ==null || toUser == null)
// {
// System.out.println("User is null");
// throw new SQLException();
// }
ChatMessage chatMessage = new ChatMessage();
messageCipher = messageCipherRepository.save(messageCipher);
chatMessage.setMessageCipher(messageCipher);
chatMessage.setFromUser(fromUser);
chatMessage.setToUser(toUser);
chatMessageRepository.save(chatMessage);
chatMessage = chatMessageRepository.save(chatMessage);
return myConversionService.convertToChatMessageDTO(chatMessage);
}

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

@ -2,6 +2,8 @@ package org.ros.chatto.service;
import java.util.List;
import javax.transaction.Transactional;
import org.ros.chatto.dto.UserRegistrationDTO;
import org.ros.chatto.model.ChatUser;
import org.ros.chatto.model.Role;
@ -31,6 +33,7 @@ public class UserServiceImpl implements UserService{
UserRepositoryCustom userRepositoryCustom;
@Override
@Transactional
public void saveChatUser(ChatUser user) {
// TODO Auto-generated method stub
ChatUser changedUser = userRepository.save(user);
@ -41,6 +44,7 @@ public class UserServiceImpl implements UserService{
}
@Override
@Transactional
public void registerUser(UserRegistrationDTO userRegistrationDTO) {
// TODO Auto-generated method stub
ChatUser user = new ChatUser();

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

@ -62,7 +62,6 @@ function handleChangePassphraseForm() {
messageCiphers.push(messageCipherNewObj);
// let messageCipherJson = JSON.stringify(messageCipherNewObj);
let fromUser = sessionStorage.getItem('username');
let chatMessageDTO = {
"toUser": user,
"fromUser": username,

4
chatto/src/main/resources/templates/fragments/head.html

@ -16,11 +16,11 @@
<link th:href="@{/css/master.css}" href="../static/css/master.css" rel="stylesheet">
<link th:href="@{/css/colors.css}" href="../static/css/colors.css" rel="stylesheet">
</link>
<script th:inline="javascript">
var hostAddress = window.location.host;
/* var hostAddress2 = [[#{test.bindAddress}]]; */
console.log("hostname" + window.location.host);
// console.log("hostname" + window.location.host);
</script>
<meta charset="UTF-8">

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

@ -17,7 +17,7 @@
<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 text-white bg-primary mb-3 card-form rounded mx-auto" id="login-card">
<div class="card-body rounded">
<!-- <h4 class="card-title">Chat</h4> -->
@ -36,22 +36,19 @@
</div> -->
<div class="card-text">
<h2 class="card-title">Register</h2>
<h2 class="card-title text-center">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>
<input th:classappend="${#fields.hasErrors('userName')} ? 'is-invalid' : ''" class="form-control" th:field="*{userName}" type="text" name="username" required>
<small class="form-text">Username must be alphanumeric</small>
<span th:if="${#fields.hasErrors('userName')}" class="help-block text-danger" th:errors="*{userName}"></span>
</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>
<input th:classappend="${#fields.hasErrors('password')} ? 'is-invalid' : ''" class="form-control" th:field="*{password}" type="password" name="password" id="password" required>
<span th:if="${#fields.hasErrors('password')}" class="help-block text-danger" th:errors="*{password}"></span>
</div>
<div class="form-group">
<label for="password-repeat">Repeat password: </label>

Loading…
Cancel
Save