zz
This commit is contained in:
parent
d8ce654df6
commit
3ea46b584a
@ -51,10 +51,7 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
@ -74,12 +71,19 @@
|
|||||||
<version>2.1.2</version>
|
<version>2.1.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
|
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.modelmapper</groupId>
|
||||||
|
<artifactId>modelmapper</artifactId>
|
||||||
|
<version>2.3.5</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.ros.chatto.controller;
|
package org.ros.chatto;
|
||||||
|
|
||||||
|
import org.modelmapper.ModelMapper;
|
||||||
import org.ros.chatto.security.AuthenticationSuccessHandlerImpl;
|
import org.ros.chatto.security.AuthenticationSuccessHandlerImpl;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -7,9 +8,16 @@ import org.springframework.security.web.authentication.AuthenticationSuccessHand
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class BeanConfigurations {
|
public class BeanConfigurations {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public AuthenticationSuccessHandler authenticationSuccessHandler() {
|
public AuthenticationSuccessHandler authenticationSuccessHandler() {
|
||||||
return new AuthenticationSuccessHandlerImpl();
|
return new AuthenticationSuccessHandlerImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ModelMapper modelMapper() {
|
||||||
|
ModelMapper modelMapper = new ModelMapper();
|
||||||
|
return modelMapper;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ public class ChattoApplication extends SpringBootServletInitializer {
|
|||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(ChattoApplication.class, args);
|
SpringApplication.run(ChattoApplication.class, args);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package org.ros.chatto;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public final class RestAuthenticationEntryPoint
|
||||||
|
extends BasicAuthenticationEntryPoint {
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public void commence(
|
||||||
|
// HttpServletRequest request,
|
||||||
|
// HttpServletResponse response,
|
||||||
|
// AuthenticationException authException) throws IOException {
|
||||||
|
//
|
||||||
|
// response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
|
||||||
|
// "Unauthorized");
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
response.addHeader("WWW-Authenticate", "Basic realm=" +getRealmName());
|
||||||
|
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
PrintWriter writer = response.getWriter();
|
||||||
|
writer.println("HTTP Status 401 - " + authEx.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
setRealmName("Chatto");
|
||||||
|
super.afterPropertiesSet();
|
||||||
|
}
|
||||||
|
}
|
20
chatto/src/main/java/org/ros/chatto/WebConfig.java
Normal file
20
chatto/src/main/java/org/ros/chatto/WebConfig.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package org.ros.chatto;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
//@EnableWebMvc
|
||||||
|
public class WebConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
|
registry.addMapping("/api/**")
|
||||||
|
.allowedOrigins("*")
|
||||||
|
.allowedMethods("POST","GET","OPTIONS")
|
||||||
|
.allowedHeaders("*")
|
||||||
|
.allowCredentials(false).maxAge(3600);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@ import org.ros.chatto.security.MyUserDetailsService;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
@ -18,69 +18,119 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
|||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthenticationSuccessHandler authenticationSuccessHandler;
|
private AuthenticationSuccessHandler authenticationSuccessHandler;
|
||||||
@Autowired
|
@Autowired
|
||||||
private MyUserDetailsService myUserDetailsService;
|
private MyUserDetailsService myUserDetailsService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private PasswordEncoder passwordEncoder;
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
|
||||||
// @SuppressWarnings("deprecation")
|
// @SuppressWarnings("deprecation")
|
||||||
@Bean
|
@Bean
|
||||||
public AuthenticationProvider authenticationProvider()
|
public AuthenticationProvider authenticationProvider() {
|
||||||
{
|
|
||||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||||
provider.setUserDetailsService(myUserDetailsService);
|
provider.setUserDetailsService(myUserDetailsService);
|
||||||
provider.setPasswordEncoder(passwordEncoder);
|
provider.setPasswordEncoder(passwordEncoder);
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public static PasswordEncoder passwordEncoder() {
|
public static PasswordEncoder passwordEncoder() {
|
||||||
return new BCryptPasswordEncoder();
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Order(1)
|
||||||
|
public static class ApiWebSecurity extends WebSecurityConfigurerAdapter {
|
||||||
|
@Autowired
|
||||||
|
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.csrf().disable()
|
||||||
|
.exceptionHandling()
|
||||||
|
|
||||||
|
.and()
|
||||||
|
// .cors().and()
|
||||||
|
.antMatcher("/api/**")
|
||||||
|
.authorizeRequests()
|
||||||
|
// .antMatchers("/perform-login").permitAll()
|
||||||
|
.anyRequest()
|
||||||
|
// .hasAnyRole("USER", "ADMIN", "SUPER_USER")
|
||||||
|
.authenticated()
|
||||||
|
.and().httpBasic()
|
||||||
|
.authenticationEntryPoint(restAuthenticationEntryPoint)
|
||||||
|
// .and()
|
||||||
|
// .logout().invalidateHttpSession(true).clearAuthentication(true)
|
||||||
|
// .logoutRequestMatcher(new AntPathRequestMatcher("/api/perform_logout"))
|
||||||
|
// .logoutSuccessUrl("/").permitAll()
|
||||||
|
// .and()
|
||||||
|
// .formLogin()
|
||||||
|
// .loginProcessingUrl("/api/perform_login").permitAll()
|
||||||
|
// .and()
|
||||||
|
// .formLogin()
|
||||||
|
// .and()
|
||||||
|
// .logout();
|
||||||
|
;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Order(2)
|
||||||
|
public static class FormWebSecurity extends WebSecurityConfigurerAdapter {
|
||||||
|
@Override
|
||||||
|
|
||||||
|
protected void configure(HttpSecurity httpSecurity) throws Exception {
|
||||||
|
httpSecurity.authorizeRequests()
|
||||||
|
// .antMatchers(HttpMethod.POST, "/api/**").permitAll()
|
||||||
|
.antMatchers("/", "perform_login","/login*", "/registration", "/perform_registration", "/css/**", "/js/**",
|
||||||
|
"/images/**")
|
||||||
|
.permitAll()
|
||||||
|
// .antMatchers("/","/api**","/api/**","/login*","/registration","/perform_registration","/css/**", "/js/**", "/images/**").permitAll()
|
||||||
|
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN", "SUPER_USER")
|
||||||
|
.antMatchers("/admin/**").hasAnyRole("ADMIN", "SUPER_USER")
|
||||||
|
// .and()
|
||||||
|
// .antMatcher("/api/**")
|
||||||
|
// .authorizeRequests()
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
|
||||||
|
.and()
|
||||||
|
|
||||||
|
.formLogin()
|
||||||
|
.loginPage("/login").permitAll()
|
||||||
|
.loginProcessingUrl("/login")
|
||||||
|
// .successHandler(authenticationSuccessHandler)
|
||||||
|
// .failureUrl("/?login_error")
|
||||||
|
.and()
|
||||||
|
.logout().invalidateHttpSession(true).clearAuthentication(true)
|
||||||
|
.logoutRequestMatcher(new AntPathRequestMatcher("/perform_logout"))
|
||||||
|
// .logoutSuccessUrl("/").permitAll()
|
||||||
|
// .and().httpBasic();
|
||||||
|
// .and().cors()
|
||||||
|
// .and().csrf().disable();
|
||||||
|
;
|
||||||
|
// httpSecurity
|
||||||
|
// .csrf().disable()
|
||||||
|
// .authorizeRequests().antMatchers("login").permitAll()
|
||||||
|
// .anyRequest().authenticated()
|
||||||
|
// .and()
|
||||||
|
// .formLogin()
|
||||||
|
// .loginPage("/login").permitAll()
|
||||||
|
// .and()
|
||||||
|
// .logout().invalidateHttpSession(true)
|
||||||
|
// .clearAuthentication(true)
|
||||||
|
// .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||||
|
// .logoutSuccessUrl("/").permitAll();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(HttpSecurity httpSecurity) throws Exception {
|
|
||||||
httpSecurity.authorizeRequests()
|
|
||||||
.antMatchers(HttpMethod.POST, "/api/**").permitAll()
|
|
||||||
.antMatchers("/","/login*","/registration","/perform_registration","/css/**", "/js/**", "/images/**").permitAll()
|
|
||||||
// .antMatchers("/","/api**","/api/**","/login*","/registration","/perform_registration","/css/**", "/js/**", "/images/**").permitAll()
|
|
||||||
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN","SUPER_USER")
|
|
||||||
.antMatchers("/admin/**").hasAnyRole("ADMIN","SUPER_USER")
|
|
||||||
.anyRequest()
|
|
||||||
.authenticated()
|
|
||||||
|
|
||||||
.and()
|
|
||||||
|
|
||||||
.formLogin()
|
|
||||||
// .loginPage("/login").permitAll()
|
|
||||||
.loginProcessingUrl("/perform_login")
|
|
||||||
// .successHandler(authenticationSuccessHandler)
|
|
||||||
.failureUrl("/?login_error")
|
|
||||||
.and()
|
|
||||||
.logout().invalidateHttpSession(true)
|
|
||||||
.clearAuthentication(true)
|
|
||||||
.logoutRequestMatcher(new AntPathRequestMatcher("/perform_logout"))
|
|
||||||
.logoutSuccessUrl("/").permitAll()
|
|
||||||
.and().cors().and().csrf().disable();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// httpSecurity
|
|
||||||
// .csrf().disable()
|
|
||||||
// .authorizeRequests().antMatchers("login").permitAll()
|
|
||||||
// .anyRequest().authenticated()
|
|
||||||
// .and()
|
|
||||||
// .formLogin()
|
|
||||||
// .loginPage("/login").permitAll()
|
|
||||||
// .and()
|
|
||||||
// .logout().invalidateHttpSession(true)
|
|
||||||
// .clearAuthentication(true)
|
|
||||||
// .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
|
||||||
// .logoutSuccessUrl("/").permitAll();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
// auth.inMemoryAuthentication()
|
// auth.inMemoryAuthentication()
|
||||||
@ -113,6 +163,6 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|||||||
// auth.userDetailsService(myUserDetailsService);
|
// auth.userDetailsService(myUserDetailsService);
|
||||||
// }
|
// }
|
||||||
// auth.userDetailsService(myUserDetailsService);
|
// auth.userDetailsService(myUserDetailsService);
|
||||||
|
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
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.model.MessageCipher;
|
||||||
|
import org.ros.chatto.service.ChatService;
|
||||||
|
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/chat")
|
||||||
|
public class ChatMessageController {
|
||||||
|
@Autowired
|
||||||
|
private ChatService chatService;
|
||||||
|
|
||||||
|
@PostMapping(value = "/post/message", consumes = { "application/json" })
|
||||||
|
@ResponseBody
|
||||||
|
public ResponseEntity<ChatMessageDTO> newMessage(@RequestBody ChatMessageDTO chatMessageDTO, Principal principal) {
|
||||||
|
MessageCipher 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/get/messages/{userName}")
|
||||||
|
@ResponseBody
|
||||||
|
public List<ChatMessageDTO> sendAllMessages(@PathVariable String userName, Principal principal) {
|
||||||
|
List<ChatMessageDTO> chatMessageDTOs = chatService.getAllMessages(principal.getName(), userName);
|
||||||
|
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 );
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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);
|
||||||
|
//}
|
@ -1,27 +1,38 @@
|
|||||||
package org.ros.chatto.controller;
|
package org.ros.chatto.controller;
|
||||||
|
|
||||||
import org.ros.chatto.repository.UserRepositoryCustom;
|
import java.security.Principal;
|
||||||
import org.ros.chatto.repository.UserRoleRepository;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.ros.chatto.model.ChatMessage;
|
||||||
|
import org.ros.chatto.model.ChatUser;
|
||||||
|
import org.ros.chatto.model.MessageCipher;
|
||||||
|
import org.ros.chatto.model.UserRole;
|
||||||
|
import org.ros.chatto.repository.ChatMessageRepository;
|
||||||
import org.ros.chatto.repository.MessageCipherRepository;
|
import org.ros.chatto.repository.MessageCipherRepository;
|
||||||
import org.ros.chatto.repository.RoleRepository;
|
import org.ros.chatto.repository.RoleRepository;
|
||||||
import org.ros.chatto.repository.UserRepository;
|
import org.ros.chatto.repository.UserRepository;
|
||||||
|
import org.ros.chatto.repository.UserRepositoryCustom;
|
||||||
|
import org.ros.chatto.repository.UserRoleRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.ros.chatto.model.ChatUser;
|
|
||||||
import org.ros.chatto.model.MessageCipher;
|
|
||||||
import org.ros.chatto.model.UserRole;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api")
|
@RequestMapping("/api")
|
||||||
|
//@CrossOrigin(origins = "*", allowCredentials = "true", allowedHeaders = "*")
|
||||||
public class DemoRestController {
|
public class DemoRestController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -34,6 +45,8 @@ public class DemoRestController {
|
|||||||
UserRoleRepository userRoleRepository;
|
UserRoleRepository userRoleRepository;
|
||||||
@Autowired
|
@Autowired
|
||||||
MessageCipherRepository messageCipherRepository;
|
MessageCipherRepository messageCipherRepository;
|
||||||
|
@Autowired
|
||||||
|
ChatMessageRepository chatMessageRepository;
|
||||||
|
|
||||||
@GetMapping("/users")
|
@GetMapping("/users")
|
||||||
public List<ChatUser> getAllUsers() {
|
public List<ChatUser> getAllUsers() {
|
||||||
@ -45,23 +58,35 @@ public class DemoRestController {
|
|||||||
return userRepositoryCustom.getAllUserNames("hmm");
|
return userRepositoryCustom.getAllUserNames("hmm");
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/user")
|
@GetMapping("/user_old")
|
||||||
public ChatUser getUser() {
|
public ChatUser getUser() {
|
||||||
return userRepository.findByUserName("hmm");
|
return userRepository.findByUserName("hmm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/user")
|
||||||
|
public ChatUser currentUserName(Principal principal) {
|
||||||
|
ChatUser user = userRepository.findByUserName(principal.getName());
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/roles")
|
@GetMapping("/roles")
|
||||||
public List<UserRole> getAllRoles()
|
public List<UserRole> getAllRoles()
|
||||||
{
|
{
|
||||||
return userRoleRepository.findAll();
|
return userRoleRepository.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/messages")
|
@GetMapping("/ciphers")
|
||||||
public List<MessageCipher> getAllCiphers()
|
public List<MessageCipher> getAllCiphers()
|
||||||
{
|
{
|
||||||
return messageCipherRepository.findAll();
|
return messageCipherRepository.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/messages")
|
||||||
|
public List<ChatMessage> getAllMessages()
|
||||||
|
{
|
||||||
|
return chatMessageRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
// @RequestMapping(value = "/", method = RequestMethod.POST)
|
// @RequestMapping(value = "/", method = RequestMethod.POST)
|
||||||
// public ResponseEntity<Car> update(@RequestBody Car car) {
|
// public ResponseEntity<Car> update(@RequestBody Car car) {
|
||||||
//
|
//
|
||||||
@ -80,5 +105,20 @@ public class DemoRestController {
|
|||||||
messageCipherRepository.save(messageCipher);
|
messageCipherRepository.save(messageCipher);
|
||||||
return new ResponseEntity<MessageCipher>(HttpStatus.OK);
|
return new ResponseEntity<MessageCipher>(HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/logout")
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
package org.ros.chatto.controller;
|
package org.ros.chatto.controller;
|
||||||
import org.ros.chatto.repository.UserRepositoryCustom;
|
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
|
import org.ros.chatto.dto.ChatMessageDTO;
|
||||||
|
import org.ros.chatto.service.UserService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
@ -23,15 +30,46 @@ public class TestController {
|
|||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class Home {
|
public class Home {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
UserRepositoryCustom userRepositoryCustom;
|
UserService userService;
|
||||||
|
|
||||||
@RequestMapping("/")
|
@RequestMapping("/")
|
||||||
public ModelAndView showPage() {
|
public ModelAndView showPage(Principal principal) {
|
||||||
ModelAndView mv = new ModelAndView("home");
|
ModelAndView mv = new ModelAndView("home");
|
||||||
mv.addObject("message", "Welcome!");
|
mv.addObject("message", "Welcome!");
|
||||||
mv.addObject("userNames", userRepositoryCustom.getAllUserNames("hmm"));
|
// mv.addObject("userNames", userService.findAllOtherUsers(principal.getName()));
|
||||||
return mv;
|
return mv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/crypt")
|
||||||
|
public String showCrypt() {
|
||||||
|
return "crypto";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/chat")
|
||||||
|
public ModelAndView showChat(Principal principal) {
|
||||||
|
ModelAndView modelAndView = new ModelAndView("chat");
|
||||||
|
modelAndView.addObject(new ChatMessageDTO());
|
||||||
|
// modelAndView.addObject("userNames", userRepositoryCustom.getAllUserNames("hmm"));
|
||||||
|
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
// Set<String> roles = authentication.getAuthorities().stream().map(r -> r.getAuthority())
|
||||||
|
// .collect(Collectors.toSet());
|
||||||
|
// for (String r : roles) {
|
||||||
|
// System.out.println(r);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// boolean hasUserRole = authentication.getAuthorities().stream()
|
||||||
|
// .anyMatch(r -> r.getAuthority().equals("ROLE_USER"));
|
||||||
|
|
||||||
|
boolean isAdmin = authentication.getAuthorities().stream()
|
||||||
|
.anyMatch(r -> r.getAuthority().equals("ROLE_ADMIN") || r.getAuthority().equals("ROLE_SUPER_USER"));
|
||||||
|
System.out.println("Is admin? " + isAdmin);
|
||||||
|
modelAndView.addObject("userNames", userService.findAllOtherUsers(principal.getName()));
|
||||||
|
return modelAndView;
|
||||||
|
}
|
||||||
// public String showHome(Model model)
|
// public String showHome(Model model)
|
||||||
// {
|
// {
|
||||||
// model.addAttribute("message", "Welcome");
|
// model.addAttribute("message", "Welcome");
|
||||||
|
@ -3,7 +3,7 @@ package org.ros.chatto.controller;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.ros.chatto.model.UserDTO;
|
import org.ros.chatto.dto.UserRegistrationDTO;
|
||||||
import org.ros.chatto.service.UserService;
|
import org.ros.chatto.service.UserService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
@ -21,14 +21,14 @@ public class RegisterController {
|
|||||||
public ModelAndView registrationForm()
|
public ModelAndView registrationForm()
|
||||||
{
|
{
|
||||||
ModelAndView modelAndView = new ModelAndView("registration");
|
ModelAndView modelAndView = new ModelAndView("registration");
|
||||||
modelAndView.addObject("userDTO",new UserDTO());
|
modelAndView.addObject("userDTO",new UserRegistrationDTO());
|
||||||
return modelAndView;
|
return modelAndView;
|
||||||
}
|
}
|
||||||
@PostMapping("/perform_registration")
|
@PostMapping("/perform_registration")
|
||||||
public ModelAndView performRegistration(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, @ModelAttribute("userDTO") UserDTO userDTO)
|
public ModelAndView performRegistration(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, @ModelAttribute("userDTO") UserRegistrationDTO userRegistrationDTO)
|
||||||
{
|
{
|
||||||
ModelAndView modelAndView = new ModelAndView("user/home");
|
ModelAndView modelAndView = new ModelAndView("user/home");
|
||||||
userService.registerUser(userDTO);
|
userService.registerUser(userRegistrationDTO);
|
||||||
return modelAndView;
|
return modelAndView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
chatto/src/main/java/org/ros/chatto/datae.sql
Normal file
39
chatto/src/main/java/org/ros/chatto/datae.sql
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
--INSERT INTO `admins` (`admin_id`, `user_id`) VALUES
|
||||||
|
--(1, 3);
|
||||||
|
--INSERT INTO `chat_messages` (`m_id`, `from_user`, `to_user`, `message`, `message_time`) VALUES
|
||||||
|
--(5, 3, 6, 3, '2019-09-28 15:42:15'),
|
||||||
|
--(6, 8, 3, 9, '2019-09-30 10:38:18'),
|
||||||
|
--(7, 8, 6, 10, '2019-09-30 10:40:31'),
|
||||||
|
--(8, 8, 3, 11, '2019-09-30 10:42:54'),
|
||||||
|
--(9, 3, 8, 4, '2019-09-30 12:40:16'),
|
||||||
|
--(10, 8, 3, 12, '2019-09-30 13:47:41'),
|
||||||
|
--(11, 8, 13, 13, '2019-09-30 13:47:48'),
|
||||||
|
--(12, 8, 6, 14, '2019-09-30 13:48:00'),
|
||||||
|
--(13, 8, 3, 15, '2019-10-01 06:34:10'),
|
||||||
|
--(14, 8, 3, 16, '2019-10-01 06:37:19'),
|
||||||
|
--(15, 8, 13, 17, '2019-10-01 06:56:07'),
|
||||||
|
--(16, 8, 13, 18, '2019-10-01 20:42:32'),
|
||||||
|
--(17, 3, 6, 19, '2019-10-01 20:44:59'),
|
||||||
|
--(18, 3, 13, 20, '2019-10-02 04:47:23'),
|
||||||
|
--(19, 3, 8, 21, '2019-10-02 04:56:07'),
|
||||||
|
--(20, 3, 8, 22, '2019-10-02 04:56:19'),
|
||||||
|
--(21, 3, 3, 23, '2019-10-02 06:42:21'),
|
||||||
|
--(22, 8, 3, 24, '2019-10-02 07:14:02'),
|
||||||
|
--(23, 3, 8, 25, '2019-10-02 09:07:13'),
|
||||||
|
--(24, 8, 13, 26, '2019-10-02 09:17:28'),
|
||||||
|
--(25, 8, 3, 27, '2019-10-02 09:18:54'),
|
||||||
|
--(26, 8, 3, 28, '2019-10-02 09:20:49'),
|
||||||
|
--(27, 3, 8, 29, '2019-10-02 09:47:29'),
|
||||||
|
--(28, 3, 8, 30, '2019-10-02 09:47:58'),
|
||||||
|
--(29, 3, 8, 31, '2019-10-02 10:14:32');
|
||||||
|
--
|
||||||
|
--INSERT INTO `chatmessage` (`Id`, `Message`, `userName`, `MsgTime`, `colorSelected`) VALUES
|
||||||
|
--(400, '', 'dae', '2019/08/19 12:58:52', '333'),
|
||||||
|
--(401, 'aegqe\n', 'dae', '2019/08/19 12:58:52', '333');
|
||||||
|
--
|
||||||
|
--
|
||||||
|
--INSERT INTO `users` (`user_id`, `name`, `password`, `join_date`) VALUES
|
||||||
|
--(3, 'user2', '$2a$10$nLhkNrGu0/2ahSlULoQ0ROvUK2sRTEZBV014BLB/W9nBSMxy0rTGy', '2019-09-23 07:44:59'),
|
||||||
|
--(6, 'novo', '$2a$10$nLhkNrGu0/2ahSlULoQ0ROvUK2sRTEZBV014BLB/W9nBSMxy0rTGy', '2019-09-23 07:45:06'),
|
||||||
|
--(8, 'hmm', '$2a$10$k4tASmvqJ1mPA7avuzAnSO1KmWOmNhp7K8Y5Yg.dV/VXMX2L73/Ma', '2019-09-23 07:40:56'),
|
||||||
|
--(13, 'hmm2', '$2a$10$F.lMGPDXOguXWehMf1fvq.7XqzbFZWweLv3DYwB.1zpDEuPDcKBv6', '2019-09-23 13:46:33');
|
14
chatto/src/main/java/org/ros/chatto/dto/ChatMessageDTO.java
Normal file
14
chatto/src/main/java/org/ros/chatto/dto/ChatMessageDTO.java
Normal file
@ -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 ChatMessageDTO {
|
||||||
|
private String toUser, fromUser;
|
||||||
|
private MessageCipher messageCipher;
|
||||||
|
private Date messageTime;
|
||||||
|
}
|
14
chatto/src/main/java/org/ros/chatto/dto/UserPublicDTO.java
Normal file
14
chatto/src/main/java/org/ros/chatto/dto/UserPublicDTO.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
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;
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package org.ros.chatto.model;
|
package org.ros.chatto.dto;
|
||||||
|
|
||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
|
|
||||||
public class UserDTO {
|
public class UserRegistrationDTO {
|
||||||
private String userName;
|
private String userName;
|
||||||
@Transient
|
@Transient
|
||||||
private String password;
|
private String password;
|
||||||
|
@ -29,7 +29,9 @@ public class ChatMessage {
|
|||||||
@OneToOne
|
@OneToOne
|
||||||
@JoinColumn(name = "to_user")
|
@JoinColumn(name = "to_user")
|
||||||
private ChatUser toUser;
|
private ChatUser toUser;
|
||||||
private String message;
|
@OneToOne
|
||||||
|
@JoinColumn(name = "message")
|
||||||
|
private MessageCipher messageCipher;
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
private Date messageTime;
|
private Date messageTime;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package org.ros.chatto.model;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
@ -21,7 +22,7 @@ public class Role {
|
|||||||
@Column(name = "role_name")
|
@Column(name = "role_name")
|
||||||
private String name;
|
private String name;
|
||||||
private String description;
|
private String description;
|
||||||
@OneToMany(mappedBy = "role")
|
@OneToMany(mappedBy = "role", cascade = CascadeType.ALL)
|
||||||
@JsonBackReference
|
@JsonBackReference
|
||||||
private Set<UserRole> userRoles = new HashSet<>();
|
private Set<UserRole> userRoles = new HashSet<>();
|
||||||
public int getRoleId() {
|
public int getRoleId() {
|
||||||
|
@ -1,8 +1,25 @@
|
|||||||
package org.ros.chatto.repository;
|
package org.ros.chatto.repository;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.ros.chatto.model.ChatMessage;
|
import org.ros.chatto.model.ChatMessage;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
public interface ChatMessageRepository extends JpaRepository<ChatMessage, Long> {
|
public interface ChatMessageRepository extends JpaRepository<ChatMessage, Long> {
|
||||||
|
// @Query("select r from RoleRepository where name = ?1")
|
||||||
|
// @Query("select ur from UserRole ur where ur.user.userID = ?1")
|
||||||
|
// @Query("select m from ChatMessage m where m.toUser.userID = ?1 or m.toUser.userID = ?2 and "
|
||||||
|
// + "m.fromUser.userID = ?1 or m.fromUser.userID = ?2 order by m.messageTime asc")
|
||||||
|
@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);
|
||||||
|
|
||||||
|
@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) and"
|
||||||
|
+ "(m.messageTime >= ?3) order by m.messageTime asc")
|
||||||
|
public List<ChatMessage> getNewMessages(String fromUser, String toUser, Date lastMessageTime);
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,10 @@ class UserRepositoryCustomImpl implements UserRepositoryCustom{
|
|||||||
criteriaQuery.where(criteriaBuilder.notEqual(root.get("userName"), userName));
|
criteriaQuery.where(criteriaBuilder.notEqual(root.get("userName"), userName));
|
||||||
|
|
||||||
userNamesList = entityManager.createQuery(criteriaQuery).getResultList();
|
userNamesList = entityManager.createQuery(criteriaQuery).getResultList();
|
||||||
for(String un: userNamesList)
|
// for(String un: userNamesList)
|
||||||
{
|
// {
|
||||||
System.out.println(un);
|
// System.out.println(un);
|
||||||
}
|
// }
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// TODO: handle exception
|
// TODO: handle exception
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
187
chatto/src/main/java/org/ros/chatto/scheme.sql
Normal file
187
chatto/src/main/java/org/ros/chatto/scheme.sql
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
-- Database: `chatto_db`
|
||||||
|
--
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `admins`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `admins` (
|
||||||
|
`admin_id` int(11) NOT NULL,
|
||||||
|
`user_id` int(11) NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `admins`
|
||||||
|
--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `chatmessage`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `chatmessage` (
|
||||||
|
`Id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`Message` varchar(4000) NOT NULL,
|
||||||
|
`userName` varchar(100) NOT NULL,
|
||||||
|
`MsgTime` varchar(45) NOT NULL,
|
||||||
|
`colorSelected` varchar(45) NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `chatmessage`
|
||||||
|
--
|
||||||
|
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `chat_messages`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `chat_messages` (
|
||||||
|
`m_id` bigint(20) NOT NULL,
|
||||||
|
`from_user` int(11) NOT NULL,
|
||||||
|
`to_user` int(11) NOT NULL,
|
||||||
|
`message` int(10) NOT NULL,
|
||||||
|
`message_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `chat_messages`
|
||||||
|
--
|
||||||
|
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `total_messages`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `total_messages` (
|
||||||
|
`t_id` int(101) NOT NULL,
|
||||||
|
`from_user` int(11) NOT NULL,
|
||||||
|
`to_user` int(11) NOT NULL,
|
||||||
|
`total_messages` int(11) NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `users`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `users` (
|
||||||
|
`user_id` int(11) NOT NULL,
|
||||||
|
`name` varchar(10) NOT NULL,
|
||||||
|
`password` varchar(80) NOT NULL,
|
||||||
|
`join_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `users`
|
||||||
|
--
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for dumped tables
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for table `admins`
|
||||||
|
--
|
||||||
|
ALTER TABLE `admins`
|
||||||
|
ADD PRIMARY KEY (`admin_id`),
|
||||||
|
ADD UNIQUE KEY `user_id_2` (`user_id`),
|
||||||
|
ADD KEY `admin_id` (`admin_id`),
|
||||||
|
ADD KEY `user_id` (`user_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for table `chatmessage`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatmessage`
|
||||||
|
ADD PRIMARY KEY (`Id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for table `chat_messages`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chat_messages`
|
||||||
|
ADD PRIMARY KEY (`m_id`),
|
||||||
|
ADD UNIQUE KEY `identifier_message_number` (`m_id`),
|
||||||
|
ADD KEY `identifier_message_number_2` (`m_id`),
|
||||||
|
ADD KEY `from_user` (`from_user`,`to_user`),
|
||||||
|
ADD KEY `message` (`message`),
|
||||||
|
ADD KEY `FOREIGN KEY TO USER IN MESSAGES TABLE` (`to_user`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for table `total_messages`
|
||||||
|
--
|
||||||
|
ALTER TABLE `total_messages`
|
||||||
|
ADD PRIMARY KEY (`t_id`),
|
||||||
|
ADD UNIQUE KEY `identifier` (`t_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for table `users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `users`
|
||||||
|
ADD PRIMARY KEY (`user_id`),
|
||||||
|
ADD UNIQUE KEY `name` (`name`),
|
||||||
|
ADD KEY `user_id` (`user_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- AUTO_INCREMENT for dumped tables
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- AUTO_INCREMENT for table `admins`
|
||||||
|
--
|
||||||
|
ALTER TABLE `admins`
|
||||||
|
MODIFY `admin_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||||
|
--
|
||||||
|
-- AUTO_INCREMENT for table `chatmessage`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatmessage`
|
||||||
|
MODIFY `Id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=402;
|
||||||
|
--
|
||||||
|
-- AUTO_INCREMENT for table `chat_messages`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chat_messages`
|
||||||
|
MODIFY `m_id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=30;
|
||||||
|
--
|
||||||
|
-- AUTO_INCREMENT for table `total_messages`
|
||||||
|
--
|
||||||
|
ALTER TABLE `total_messages`
|
||||||
|
MODIFY `t_id` int(101) NOT NULL AUTO_INCREMENT;
|
||||||
|
--
|
||||||
|
-- AUTO_INCREMENT for table `users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `users`
|
||||||
|
MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=14;
|
||||||
|
--
|
||||||
|
-- Constraints for dumped tables
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `admins`
|
||||||
|
--
|
||||||
|
ALTER TABLE `admins`
|
||||||
|
ADD CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `chat_messages`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chat_messages`
|
||||||
|
ADD CONSTRAINT `FOREIGN KEY ENC MESSAGE TABLE` FOREIGN KEY (`message`) REFERENCES `message_ciphers` (`id`) ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `FOREIGN KEY FROM USER IN MESSAGES TABLE` FOREIGN KEY (`from_user`) REFERENCES `users` (`user_id`) ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `FOREIGN KEY TO USER IN MESSAGES TABLE` FOREIGN KEY (`to_user`) REFERENCES `users` (`user_id`) ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
|
|
||||||
|
|
||||||
|
|
17
chatto/src/main/java/org/ros/chatto/service/ChatService.java
Normal file
17
chatto/src/main/java/org/ros/chatto/service/ChatService.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package org.ros.chatto.service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.ros.chatto.dto.ChatMessageDTO;
|
||||||
|
import org.ros.chatto.model.MessageCipher;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package org.ros.chatto.service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.ros.chatto.dto.ChatMessageDTO;
|
||||||
|
import org.ros.chatto.model.ChatMessage;
|
||||||
|
import org.ros.chatto.model.ChatUser;
|
||||||
|
import org.ros.chatto.model.MessageCipher;
|
||||||
|
import org.ros.chatto.repository.ChatMessageRepository;
|
||||||
|
import org.ros.chatto.repository.MessageCipherRepository;
|
||||||
|
import org.ros.chatto.repository.UserRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ChatServiceImpl implements ChatService {
|
||||||
|
|
||||||
|
// @Autowired
|
||||||
|
// UserService userService;
|
||||||
|
@Autowired
|
||||||
|
UserRepository userRepository;
|
||||||
|
@Autowired
|
||||||
|
MessageCipherRepository messageCipherRepository;
|
||||||
|
@Autowired
|
||||||
|
ChatMessageRepository chatMessageRepository;
|
||||||
|
@Autowired
|
||||||
|
MyConversionService myConversionService;
|
||||||
|
|
||||||
|
public void saveNewMessage(String fromUserName, String toUserName, MessageCipher messageCipher) {
|
||||||
|
|
||||||
|
ChatUser fromUser = userRepository.findByUserName(fromUserName);
|
||||||
|
ChatUser toUser = userRepository.findByUserName(toUserName);
|
||||||
|
ChatMessage chatMessage = new ChatMessage();
|
||||||
|
messageCipher = messageCipherRepository.save(messageCipher);
|
||||||
|
chatMessage.setMessageCipher(messageCipher);
|
||||||
|
chatMessage.setFromUser(fromUser);
|
||||||
|
chatMessage.setToUser(toUser);
|
||||||
|
|
||||||
|
chatMessageRepository.save(chatMessage);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ChatMessageDTO> getAllMessages(String fromUser, String toUser) {
|
||||||
|
List<ChatMessage> chatMessages = chatMessageRepository.getAllMessages(fromUser, toUser);
|
||||||
|
List<ChatMessageDTO> chatMessageDTOs = myConversionService.convertToChatMessageDTOs(chatMessages);
|
||||||
|
return chatMessageDTOs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ChatMessageDTO> getMessagePage(int page, int size) {
|
||||||
|
// Sort sort = Sort
|
||||||
|
Page<ChatMessage> chatMessages = chatMessageRepository.findAll(PageRequest.of(page, size));
|
||||||
|
List<ChatMessageDTO> chatMessageDTOs = myConversionService.convertToChatMessageDTOs(chatMessages);
|
||||||
|
return chatMessageDTOs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ChatMessageDTO> getNewMessages(String fromUser, String toUser, Date lastMessageTime) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
List<ChatMessage> chatMessages = chatMessageRepository.getNewMessages(fromUser, toUser, lastMessageTime);
|
||||||
|
// List<ChatMessageDTO> chatMessageDTOs
|
||||||
|
return myConversionService.convertToChatMessageDTOs(chatMessages);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package org.ros.chatto.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.modelmapper.ModelMapper;
|
||||||
|
import org.ros.chatto.dto.ChatMessageDTO;
|
||||||
|
import org.ros.chatto.model.ChatMessage;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
|
||||||
|
//private PostDto convertToDto(Post post) {
|
||||||
|
// PostDto postDto = modelMapper.map(post, PostDto.class);
|
||||||
|
// postDto.setSubmissionDate(post.getSubmissionDate(),
|
||||||
|
// userService.getCurrentUser().getPreference().getTimezone());
|
||||||
|
// return postDto;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//private Post convertToEntity(PostDto postDto) throws ParseException {
|
||||||
|
// Post post = modelMapper.map(postDto, Post.class);
|
||||||
|
// post.setSubmissionDate(postDto.getSubmissionDateConverted(
|
||||||
|
// userService.getCurrentUser().getPreference().getTimezone()));
|
||||||
|
//
|
||||||
|
// if (postDto.getId() != null) {
|
||||||
|
// Post oldPost = postService.getPostById(postDto.getId());
|
||||||
|
// post.setRedditID(oldPost.getRedditID());
|
||||||
|
// post.setSent(oldPost.isSent());
|
||||||
|
// }
|
||||||
|
// return post;
|
||||||
|
//}
|
||||||
|
@Service
|
||||||
|
public class MyConversionService {
|
||||||
|
@Autowired
|
||||||
|
ModelMapper modelMapper;
|
||||||
|
|
||||||
|
public ChatMessageDTO convertToChatMessageDTO(ChatMessage chatMessage)
|
||||||
|
{
|
||||||
|
ChatMessageDTO chatMessageDTO = modelMapper.map(chatMessage, ChatMessageDTO.class);
|
||||||
|
return chatMessageDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ChatMessageDTO> convertToChatMessageDTOs(List<ChatMessage> chatMessages)
|
||||||
|
{
|
||||||
|
return chatMessages.stream()
|
||||||
|
.map(chatMessage -> convertToChatMessageDTO(chatMessage))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ChatMessageDTO> convertToChatMessageDTOs(Page<ChatMessage> chatMessages)
|
||||||
|
{
|
||||||
|
return chatMessages.stream()
|
||||||
|
.map(chatMessage -> convertToChatMessageDTO(chatMessage))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package org.ros.chatto.service;
|
package org.ros.chatto.service;
|
||||||
|
|
||||||
import org.ros.chatto.model.ChatUser;
|
import java.util.List;
|
||||||
import org.ros.chatto.model.UserDTO;
|
|
||||||
|
|
||||||
//@Service
|
import org.ros.chatto.dto.UserRegistrationDTO;
|
||||||
|
import org.ros.chatto.model.ChatUser;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
public interface UserService {
|
public interface UserService {
|
||||||
public void saveChatUser(ChatUser user);
|
public void saveChatUser(ChatUser user);
|
||||||
|
public List<String> findAllOtherUsers(String userName);
|
||||||
public void registerUser(UserDTO userDTO);
|
public void registerUser(UserRegistrationDTO userRegistrationDTO);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package org.ros.chatto.service;
|
package org.ros.chatto.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.ros.chatto.dto.UserRegistrationDTO;
|
||||||
import org.ros.chatto.model.ChatUser;
|
import org.ros.chatto.model.ChatUser;
|
||||||
import org.ros.chatto.model.Role;
|
import org.ros.chatto.model.Role;
|
||||||
import org.ros.chatto.model.UserDTO;
|
|
||||||
import org.ros.chatto.model.UserRole;
|
import org.ros.chatto.model.UserRole;
|
||||||
import org.ros.chatto.repository.UserRepository;
|
import org.ros.chatto.repository.UserRepository;
|
||||||
|
import org.ros.chatto.repository.UserRepositoryCustom;
|
||||||
import org.ros.chatto.repository.UserRoleRepository;
|
import org.ros.chatto.repository.UserRoleRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
@ -23,6 +26,9 @@ public class UserServiceImpl implements UserService{
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
RoleService roleService;
|
RoleService roleService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
UserRepositoryCustom userRepositoryCustom;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveChatUser(ChatUser user) {
|
public void saveChatUser(ChatUser user) {
|
||||||
@ -35,11 +41,11 @@ public class UserServiceImpl implements UserService{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerUser(UserDTO userDTO) {
|
public void registerUser(UserRegistrationDTO userRegistrationDTO) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
ChatUser user = new ChatUser();
|
ChatUser user = new ChatUser();
|
||||||
user.setUserName(userDTO.getUserName());
|
user.setUserName(userRegistrationDTO.getUserName());
|
||||||
user.setPassword(passwordEncoder.encode(userDTO.getPassword()));
|
user.setPassword(passwordEncoder.encode(userRegistrationDTO.getPassword()));
|
||||||
ChatUser changedUser = userRepository.save(user);
|
ChatUser changedUser = userRepository.save(user);
|
||||||
UserRole userRole = new UserRole();
|
UserRole userRole = new UserRole();
|
||||||
Role role = roleService.getRole("USER");
|
Role role = roleService.getRole("USER");
|
||||||
@ -50,4 +56,10 @@ public class UserServiceImpl implements UserService{
|
|||||||
userRoleRepository.save(userRole);
|
userRoleRepository.save(userRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> findAllOtherUsers(String userName) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return userRepositoryCustom.getAllUserNames(userName);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,4 +17,7 @@ logging.level.org.springframework.web=DEBUG
|
|||||||
logging.level.web=DEBUG
|
logging.level.web=DEBUG
|
||||||
logging.level.org.hibernate.SQL=DEBUG
|
logging.level.org.hibernate.SQL=DEBUG
|
||||||
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
|
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
|
||||||
spring.http.log-request-details=true
|
spring.http.log-request-details=true
|
||||||
|
#spring.jackson.date-format=yyyy-MM-d
|
||||||
|
spring.jackson.serialization.write-dates-as-timestamps=false
|
||||||
|
#spring.mvc.static-path-pattern=/static/**
|
24
chatto/src/main/resources/static/css/master.css
Normal file
24
chatto/src/main/resources/static/css/master.css
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
.myClass {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
#body-container {
|
||||||
|
margin: 0 auto 0 auto;
|
||||||
|
max-width: 80%;
|
||||||
|
/* vertical-align: auto; */
|
||||||
|
}
|
||||||
|
.shadow-sm {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
input[type="radio"]{
|
||||||
|
/*position:fixed;*/
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
input[type=radio]+label {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
input[type=radio]:checked+label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
input[type=radio]:focus+label {
|
||||||
|
border: 1px dotted #000;
|
||||||
|
}
|
267
chatto/src/main/resources/static/js/chat.js
Normal file
267
chatto/src/main/resources/static/js/chat.js
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
// import { sprintf } from 'sprintf-js';
|
||||||
|
// import { vsprintf } from 'sprintf-js';
|
||||||
|
/*var off_payment_method = document.getElementsByName('offline_payment_method');
|
||||||
|
var ischecked_method = false;
|
||||||
|
for ( var i = 0; i < off_payment_method.length; i++) {
|
||||||
|
if(off_payment_method[i].checked) {
|
||||||
|
ischecked_method = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!ischecked_method) { //payment method button is not checked
|
||||||
|
alert("Please choose Offline Payment Method");
|
||||||
|
}*/
|
||||||
|
var toUserRadios = document.getElementsByName('toUser');
|
||||||
|
var isCheckedUser = false;
|
||||||
|
var chatTextArea = document.getElementById('chatTextArea');
|
||||||
|
var passphraseInput = document.getElementById('passphrase');
|
||||||
|
var postNewMessageUrl = "http://192.168.1.8:8080/api/chat/post/message";
|
||||||
|
var getAllMessagesUrl = "http://192.168.1.8:8080/api/chat/get/messages/";
|
||||||
|
var getNewMessagesUrl = "http://192.168.1.8:8080/api/chat/get/messages/";
|
||||||
|
// var messageLog = [];
|
||||||
|
var username = sessionStorage.getItem('username');
|
||||||
|
var password = sessionStorage.getItem('password');
|
||||||
|
var authToken = 'Basic ' + btoa(username + ":" + password);
|
||||||
|
// var lastMessageTimeStamp;
|
||||||
|
|
||||||
|
// console.log(authToken);
|
||||||
|
// 'Basic ' + btoa("hmm" + ":" + "hmm")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
// let messageCipher = sjcl.encrypt("password", messageContent);
|
||||||
|
let messageCipher = sjcl.encrypt(passphraseInput.value, messageContent);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// function getMessages(toUser) {
|
||||||
|
// let headers = new Headers();
|
||||||
|
// let messageLog = [];
|
||||||
|
// // console.log("Token = " + btoa("hmm" + ":" + "hmm"))
|
||||||
|
|
||||||
|
// // headers.append('Accept','application/json')
|
||||||
|
// // headers.append('Content-Type', 'application/json');
|
||||||
|
// headers.append('Authorization', 'Basic ' + btoa("hmm" + ":" + "hmm"));
|
||||||
|
// let myPromise = fetch(getUrl + toUser, {
|
||||||
|
// method: 'GET',
|
||||||
|
// headers: headers
|
||||||
|
// })
|
||||||
|
// .then(response => {
|
||||||
|
// console.log(response);
|
||||||
|
// return response.json();
|
||||||
|
// })
|
||||||
|
// .then(json => {
|
||||||
|
|
||||||
|
// console.log(json);
|
||||||
|
// let i = 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 messageLine = sprintf('%s %s: %s \n', obj.messageTime, obj.fromUser, message);
|
||||||
|
// console.log(messageLine);
|
||||||
|
// // chatTextArea.append(obj.fromUser + ": " + message + "\n");
|
||||||
|
// chatTextArea.append(messageLine);
|
||||||
|
// messageLog[i++] = messageLine;
|
||||||
|
// });
|
||||||
|
// console.log(messageLog);
|
||||||
|
// // return messageLog;
|
||||||
|
|
||||||
|
// });
|
||||||
|
// return messageLog;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// async function getUserAsync(name)
|
||||||
|
// {
|
||||||
|
// let response = await fetch(`https://api.github.com/users/${name}`);
|
||||||
|
// let data = await response.json()
|
||||||
|
// return data;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// getUserAsync('yourUsernameHere')
|
||||||
|
// .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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
});
|
||||||
|
// 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));
|
||||||
|
getNewMessages(this.value, sessionStorage.getItem(this.value + '-time'))
|
||||||
|
.then(json => {
|
||||||
|
console.log(json)
|
||||||
|
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');
|
||||||
|
storedMessages.push(messageLine);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
// sessionStorage.clear();
|
||||||
|
// chatTextArea.append(JSON.stringify(storedMessages));
|
||||||
|
chatTextArea.textContent = '';
|
||||||
|
console.log("Stored messages 2 = " + storedMessages);
|
||||||
|
storedMessages.forEach(function (messageLine) {
|
||||||
|
chatTextArea.append(messageLine + '\n');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 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();
|
||||||
|
|
19
chatto/src/main/resources/static/js/loginPage.js
Normal file
19
chatto/src/main/resources/static/js/loginPage.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
function storeCredentials() {
|
||||||
|
let usernameInput = document.getElementById('username');
|
||||||
|
let passwordInput = document.getElementById('password');
|
||||||
|
let credentials = {
|
||||||
|
username: usernameInput.value,
|
||||||
|
password: passwordInput.value
|
||||||
|
}
|
||||||
|
// sessionStorage.setItem('credentials', JSON.stringify(credentials));
|
||||||
|
sessionStorage.setItem('username',usernameInput.value);
|
||||||
|
sessionStorage.setItem('password',passwordInput.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let loginForm = document.getElementById('loginForm');
|
||||||
|
loginForm.addEventListener('submit', function (e) {
|
||||||
|
storeCredentials();
|
||||||
|
})
|
||||||
|
|
||||||
|
// storeCredentials();
|
57
chatto/src/main/resources/static/js/my_Crypto.js
Normal file
57
chatto/src/main/resources/static/js/my_Crypto.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
var cipherText = sjcl.encrypt("password", "data");
|
||||||
|
console.log(cipherText);
|
||||||
|
var plainText = sjcl.decrypt("password", cipherText);
|
||||||
|
console.log(plainText);
|
||||||
|
|
||||||
|
var field = document.getElementById('crypt');
|
||||||
|
// field.innerText = plainText;
|
||||||
|
|
||||||
|
var jsonString = "{\"iv\":\"2rtnuXaJXFuQGO9ncaVkmA==\",\"v\":1,\"iter\":10000,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"H1z7o3f6qlQ=\",\"ct\":\"lF9Uno7ihjVv01M8\"}";
|
||||||
|
|
||||||
|
var myJSON = JSON.parse(jsonString);
|
||||||
|
console.log(myJSON);
|
||||||
|
|
||||||
|
// let base64 = require('base-64');
|
||||||
|
|
||||||
|
let headers = new Headers();
|
||||||
|
console.log("Token = " + btoa("hmm" + ":" + "hmm"))
|
||||||
|
|
||||||
|
// headers.append('Accept','application/json')
|
||||||
|
// headers.append('Content-Type', 'application/json');
|
||||||
|
headers.append('Authorization', 'Basic ' + btoa("hmm" + ":" + "hmm"));
|
||||||
|
// headers.append('Authorization', 'Basic aG1tOmhtbQ==');
|
||||||
|
|
||||||
|
|
||||||
|
// aG1tOmhtbQ==
|
||||||
|
var messageCipher;
|
||||||
|
fetch('http://localhost:8080/api/messages', {
|
||||||
|
method: 'GET',
|
||||||
|
headers: headers
|
||||||
|
// credentials: 'include'
|
||||||
|
}).then(response => response.json())
|
||||||
|
.then(json => {
|
||||||
|
// console.log('parsed json', JSON.stringify(json)) // access json.body here
|
||||||
|
// console.log('parsed json', json[0].messageCipher);
|
||||||
|
messageCipher = JSON.stringify(json[0].messageCipher);
|
||||||
|
console.log(messageCipher);
|
||||||
|
console.log(sjcl.decrypt("password", messageCipher));
|
||||||
|
|
||||||
|
});
|
||||||
|
// console.log("New message = " + messageCipher);
|
||||||
|
|
||||||
|
// [{"messageID":5,"fromUser":{"userID":3,"userName":"user2","joinDate":1569224699000},"toUser":{"userID":6,"userName":"novo","joinDate":1569224706000},"messageCipher":{"iv":"2rtnuXaJXFuQGO9ncaVkmA==","v":1,"mode":"ccm","adata":"","cipher":"aes","salt":"H1z7o3f6qlQ=","iter":10000,"ks":128,"ts":64,"ct":"lF9Uno7ihjVv01M8"},"messageTime":1569685335000}]
|
||||||
|
|
||||||
|
var url = 'http://localhost:8080/api/users'
|
||||||
|
xml = new XMLHttpRequest();
|
||||||
|
xml.onreadystatechange = function () {
|
||||||
|
if (xml.readyState == XMLHttpRequest.DONE) {
|
||||||
|
// alert(xhr.responseText);
|
||||||
|
console.log(xml.responseText);
|
||||||
|
// console.log(xml.getResponseHeader('X-CSRF-TOKEN'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xml.open('GET', url)
|
||||||
|
xml.setRequestHeader('Authorization', 'Basic aG1tOmhtbQ==');
|
||||||
|
xml.setRequestHeader("X-CSRF-TOKEN", "fetch");
|
||||||
|
xml.send(null);
|
||||||
|
|
60
chatto/src/main/resources/static/js/scljs.js
Normal file
60
chatto/src/main/resources/static/js/scljs.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
"use strict";var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
|
||||||
|
sjcl.cipher.aes=function(a){this.s[0][0][0]||this.O();var b,c,d,e,f=this.s[0][4],g=this.s[1];b=a.length;var h=1;if(4!==b&&6!==b&&8!==b)throw new sjcl.exception.invalid("invalid aes key size");this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&
|
||||||
|
255]]};
|
||||||
|
sjcl.cipher.aes.prototype={encrypt:function(a){return t(this,a,0)},decrypt:function(a){return t(this,a,1)},s:[[[],[],[],[],[]],[[],[],[],[],[]]],O:function(){var a=this.s[0],b=this.s[1],c=a[4],d=b[4],e,f,g,h=[],k=[],l,n,m,p;for(e=0;0x100>e;e++)k[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=l||1,g=k[g]||1)for(m=g^g<<1^g<<2^g<<3^g<<4,m=m>>8^m&255^99,c[f]=m,d[m]=f,n=h[e=h[l=h[f]]],p=0x1010101*n^0x10001*e^0x101*l^0x1010100*f,n=0x101*h[m]^0x1010100*m,e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8;for(e=
|
||||||
|
0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}};
|
||||||
|
function t(a,b,c){if(4!==b.length)throw new sjcl.exception.invalid("invalid aes block size");var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,k,l,n=d.length/4-2,m,p=4,r=[0,0,0,0];h=a.s[c];a=h[0];var q=h[1],v=h[2],w=h[3],x=h[4];for(m=0;m<n;m++)h=a[e>>>24]^q[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],k=a[f>>>24]^q[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],l=a[g>>>24]^q[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^q[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=k,g=l;for(m=
|
||||||
|
0;4>m;m++)r[c?3&-m:m]=x[e>>>24]<<24^x[f>>16&255]<<16^x[g>>8&255]<<8^x[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return r}
|
||||||
|
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.$(a.slice(b/32),32-(b&31)).slice(1);return void 0===c?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(0===a.length||0===b.length)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return 32===d?a.concat(b):sjcl.bitArray.$(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;return 0===
|
||||||
|
b?0:32*(b-1)+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(32*a.length<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b=b&31;0<c&&b&&(a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return!1;var c=0,d;for(d=0;d<a.length;d++)c|=a[d]^b[d];return 0===
|
||||||
|
c},$:function(a,b,c,d){var e;e=0;for(void 0===d&&(d=[]);32<=b;b-=32)d.push(c),c=0;if(0===b)return d.concat(a);for(e=0;e<a.length;e++)d.push(c|a[e]>>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32<b+a?c:d.pop(),1));return d},i:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]},byteswapM:function(a){var b,c;for(b=0;b<a.length;++b)c=a[b],a[b]=c>>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}};
|
||||||
|
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++)0===(d&3)&&(e=a[d/4]),b+=String.fromCharCode(e>>>8>>>8>>>8),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++)d=d<<8|a.charCodeAt(c),3===(c&3)&&(b.push(d),d=0);c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
|
||||||
|
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a=a+"00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,4*d)}};
|
||||||
|
sjcl.codec.base32={B:"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",X:"0123456789ABCDEFGHIJKLMNOPQRSTUV",BITS:32,BASE:5,REMAINING:27,fromBits:function(a,b,c){var d=sjcl.codec.base32.BASE,e=sjcl.codec.base32.REMAINING,f="",g=0,h=sjcl.codec.base32.B,k=0,l=sjcl.bitArray.bitLength(a);c&&(h=sjcl.codec.base32.X);for(c=0;f.length*d<l;)f+=h.charAt((k^a[c]>>>g)>>>e),g<d?(k=a[c]<<d-g,g+=e,c++):(k<<=d,g-=d);for(;f.length&7&&!b;)f+="=";return f},toBits:function(a,b){a=a.replace(/\s|=/g,"").toUpperCase();var c=sjcl.codec.base32.BITS,
|
||||||
|
d=sjcl.codec.base32.BASE,e=sjcl.codec.base32.REMAINING,f=[],g,h=0,k=sjcl.codec.base32.B,l=0,n,m="base32";b&&(k=sjcl.codec.base32.X,m="base32hex");for(g=0;g<a.length;g++){n=k.indexOf(a.charAt(g));if(0>n){if(!b)try{return sjcl.codec.base32hex.toBits(a)}catch(p){}throw new sjcl.exception.invalid("this isn't "+m+"!");}h>e?(h-=e,f.push(l^n>>>h),l=n<<c-h):(h+=d,l^=n<<c-h)}h&56&&f.push(sjcl.bitArray.partial(h&56,l,1));return f}};
|
||||||
|
sjcl.codec.base32hex={fromBits:function(a,b){return sjcl.codec.base32.fromBits(a,b,1)},toBits:function(a){return sjcl.codec.base32.toBits(a,1)}};
|
||||||
|
sjcl.codec.base64={B:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.B,g=0,h=sjcl.bitArray.bitLength(a);c&&(f=f.substr(0,62)+"-_");for(c=0;6*d.length<h;)d+=f.charAt((g^a[c]>>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.B,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;d<a.length;d++){h=f.indexOf(a.charAt(d));
|
||||||
|
if(0>h)throw new sjcl.exception.invalid("this isn't base64!");26<e?(e-=26,c.push(g^h>>>e),g=h<<32-e):(e+=6,g^=h<<32-e)}e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.b[0]||this.O();a?(this.F=a.F.slice(0),this.A=a.A.slice(0),this.l=a.l):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
|
||||||
|
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.F=this.Y.slice(0);this.A=[];this.l=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.A=sjcl.bitArray.concat(this.A,a);b=this.l;a=this.l=b+sjcl.bitArray.bitLength(a);if(0x1fffffffffffff<a)throw new sjcl.exception.invalid("Cannot hash more than 2^53 - 1 bits");if("undefined"!==typeof Uint32Array){var d=new Uint32Array(c),e=0;for(b=512+b-(512+b&0x1ff);b<=a;b+=512)u(this,d.subarray(16*e,
|
||||||
|
16*(e+1))),e+=1;c.splice(0,16*e)}else for(b=512+b-(512+b&0x1ff);b<=a;b+=512)u(this,c.splice(0,16));return this},finalize:function(){var a,b=this.A,c=this.F,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.l/0x100000000));for(b.push(this.l|0);b.length;)u(this,b.splice(0,16));this.reset();return c},Y:[],b:[],O:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}for(var b=0,c=2,d,e;64>b;c++){e=!0;for(d=2;d*d<=c;d++)if(0===c%d){e=
|
||||||
|
!1;break}e&&(8>b&&(this.Y[b]=a(Math.pow(c,.5))),this.b[b]=a(Math.pow(c,1/3)),b++)}}};
|
||||||
|
function u(a,b){var c,d,e,f=a.F,g=a.b,h=f[0],k=f[1],l=f[2],n=f[3],m=f[4],p=f[5],r=f[6],q=f[7];for(c=0;64>c;c++)16>c?d=b[c]:(d=b[c+1&15],e=b[c+14&15],d=b[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+b[c&15]+b[c+9&15]|0),d=d+q+(m>>>6^m>>>11^m>>>25^m<<26^m<<21^m<<7)+(r^m&(p^r))+g[c],q=r,r=p,p=m,m=n+d|0,n=l,l=k,k=h,h=d+(k&l^n&(k^l))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;f[0]=f[0]+h|0;f[1]=f[1]+k|0;f[2]=f[2]+l|0;f[3]=f[3]+n|0;f[4]=f[4]+m|0;f[5]=f[5]+p|0;f[6]=f[6]+r|0;f[7]=
|
||||||
|
f[7]+q|0}
|
||||||
|
sjcl.mode.ccm={name:"ccm",G:[],listenProgress:function(a){sjcl.mode.ccm.G.push(a)},unListenProgress:function(a){a=sjcl.mode.ccm.G.indexOf(a);-1<a&&sjcl.mode.ccm.G.splice(a,1)},fa:function(a){var b=sjcl.mode.ccm.G.slice(),c;for(c=0;c<b.length;c+=1)b[c](a)},encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,k=h.bitLength(c)/8,l=h.bitLength(g)/8;e=e||64;d=d||[];if(7>k)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;4>f&&l>>>8*f;f++);f<15-k&&(f=15-k);c=h.clamp(c,
|
||||||
|
8*(15-f));b=sjcl.mode.ccm.V(a,b,c,d,e,f);g=sjcl.mode.ccm.C(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),k=f.clamp(b,h-e),l=f.bitSlice(b,h-e),h=(h-e)/8;if(7>g)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));k=sjcl.mode.ccm.C(a,k,c,l,e,b);a=sjcl.mode.ccm.V(a,k.data,c,d,e,b);if(!f.equal(k.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");
|
||||||
|
return k.data},na:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,k=h.i;d=[h.partial(8,(b.length?64:0)|d-2<<2|f-1)];d=h.concat(d,c);d[3]|=e;d=a.encrypt(d);if(b.length)for(c=h.bitLength(b)/8,65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c])),g=h.concat(g,b),b=0;b<g.length;b+=4)d=a.encrypt(k(d,g.slice(b,b+4).concat([0,0,0])));return d},V:function(a,b,c,d,e,f){var g=sjcl.bitArray,h=g.i;e/=8;if(e%2||4>e||16<e)throw new sjcl.exception.invalid("ccm: invalid tag length");
|
||||||
|
if(0xffffffff<d.length||0xffffffff<b.length)throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");c=sjcl.mode.ccm.na(a,d,c,e,g.bitLength(b)/8,f);for(d=0;d<b.length;d+=4)c=a.encrypt(h(c,b.slice(d,d+4).concat([0,0,0])));return g.clamp(c,8*e)},C:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.i;var k=b.length,l=h.bitLength(b),n=k/50,m=n;c=h.concat([h.partial(8,f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!k)return{tag:d,data:[]};for(g=0;g<k;g+=4)g>n&&(sjcl.mode.ccm.fa(g/
|
||||||
|
k),n+=m),c[3]++,e=a.encrypt(c),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return{tag:d,data:h.clamp(b,l)}}};
|
||||||
|
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.S,k=sjcl.bitArray,l=k.i,n=[0,0,0,0];c=h(a.encrypt(c));var m,p=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4)m=b.slice(g,g+4),n=l(n,m),p=p.concat(l(c,a.encrypt(l(c,m)))),c=h(c);m=b.slice(g);b=k.bitLength(m);g=a.encrypt(l(c,[0,0,0,b]));m=k.clamp(l(m.concat([0,0,0]),g),b);n=l(n,l(m.concat([0,0,0]),g));n=a.encrypt(l(n,l(c,h(c))));
|
||||||
|
d.length&&(n=l(n,f?d:sjcl.mode.ocb2.pmac(a,d)));return p.concat(k.concat(m,k.clamp(n,e)))},decrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");e=e||64;var g=sjcl.mode.ocb2.S,h=sjcl.bitArray,k=h.i,l=[0,0,0,0],n=g(a.encrypt(c)),m,p,r=sjcl.bitArray.bitLength(b)-e,q=[];d=d||[];for(c=0;c+4<r/32;c+=4)m=k(n,a.decrypt(k(n,b.slice(c,c+4)))),l=k(l,m),q=q.concat(m),n=g(n);p=r-32*c;m=a.encrypt(k(n,[0,0,0,p]));m=k(m,h.clamp(b.slice(c),p).concat([0,
|
||||||
|
0,0]));l=k(l,m);l=a.encrypt(k(l,k(n,g(n))));d.length&&(l=k(l,f?d:sjcl.mode.ocb2.pmac(a,d)));if(!h.equal(h.clamp(l,e),h.bitSlice(b,r)))throw new sjcl.exception.corrupt("ocb: tag doesn't match");return q.concat(h.clamp(m,p))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.S,e=sjcl.bitArray,f=e.i,g=[0,0,0,0],h=a.encrypt([0,0,0,0]),h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4)h=d(h),g=f(g,a.encrypt(f(h,b.slice(c,c+4))));c=b.slice(c);128>e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);
|
||||||
|
return a.encrypt(f(d(f(h,d(h))),g))},S:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};
|
||||||
|
sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.C(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.C(!1,a,f,d,c,e);if(!g.equal(a.tag,b))throw new sjcl.exception.corrupt("gcm: tag doesn't match");return a.data},ka:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.i;e=[0,0,
|
||||||
|
0,0];f=b.slice(0);for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0<d;d--)f[d]=f[d]>>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},j:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;d<e;d+=4)b[0]^=0xffffffff&c[d],b[1]^=0xffffffff&c[d+1],b[2]^=0xffffffff&c[d+2],b[3]^=0xffffffff&c[d+3],b=sjcl.mode.gcm.ka(b,a);return b},C:function(a,b,c,d,e,f){var g,h,k,l,n,m,p,r,q=sjcl.bitArray;m=c.length;p=q.bitLength(c);r=q.bitLength(d);h=q.bitLength(e);
|
||||||
|
g=b.encrypt([0,0,0,0]);96===h?(e=e.slice(0),e=q.concat(e,[1])):(e=sjcl.mode.gcm.j(g,[0,0,0,0],e),e=sjcl.mode.gcm.j(g,e,[0,0,Math.floor(h/0x100000000),h&0xffffffff]));h=sjcl.mode.gcm.j(g,[0,0,0,0],d);n=e.slice(0);d=h.slice(0);a||(d=sjcl.mode.gcm.j(g,h,c));for(l=0;l<m;l+=4)n[3]++,k=b.encrypt(n),c[l]^=k[0],c[l+1]^=k[1],c[l+2]^=k[2],c[l+3]^=k[3];c=q.clamp(c,p);a&&(d=sjcl.mode.gcm.j(g,h,c));a=[Math.floor(r/0x100000000),r&0xffffffff,Math.floor(p/0x100000000),p&0xffffffff];d=sjcl.mode.gcm.j(g,d,a);k=b.encrypt(e);
|
||||||
|
d[0]^=k[0];d[1]^=k[1];d[2]^=k[2];d[3]^=k[3];return{tag:q.bitSlice(d,0,f),data:c}}};sjcl.misc.hmac=function(a,b){this.W=b=b||sjcl.hash.sha256;var c=[[],[]],d,e=b.prototype.blockSize/32;this.w=[new b,new b];a.length>e&&(a=b.hash(a));for(d=0;d<e;d++)c[0][d]=a[d]^909522486,c[1][d]=a[d]^1549556828;this.w[0].update(c[0]);this.w[1].update(c[1]);this.R=new b(this.w[0])};
|
||||||
|
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){if(this.aa)throw new sjcl.exception.invalid("encrypt on already updated hmac called!");this.update(a);return this.digest(a)};sjcl.misc.hmac.prototype.reset=function(){this.R=new this.W(this.w[0]);this.aa=!1};sjcl.misc.hmac.prototype.update=function(a){this.aa=!0;this.R.update(a)};sjcl.misc.hmac.prototype.digest=function(){var a=this.R.finalize(),a=(new this.W(this.w[1])).update(a).finalize();this.reset();return a};
|
||||||
|
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E4;if(0>d||0>c)throw new sjcl.exception.invalid("invalid params to pbkdf2");"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,k,l=[],n=sjcl.bitArray;for(k=1;32*l.length<(d||1);k++){e=f=a.encrypt(n.concat(b,[k]));for(g=1;g<c;g++)for(f=a.encrypt(f),h=0;h<f.length;h++)e[h]^=f[h];l=l.concat(e)}d&&(l=n.clamp(l,d));return l};
|
||||||
|
sjcl.prng=function(a){this.c=[new sjcl.hash.sha256];this.m=[0];this.P=0;this.H={};this.N=0;this.U={};this.Z=this.f=this.o=this.ha=0;this.b=[0,0,0,0,0,0,0,0];this.h=[0,0,0,0];this.L=void 0;this.M=a;this.D=!1;this.K={progress:{},seeded:{}};this.u=this.ga=0;this.I=1;this.J=2;this.ca=0x10000;this.T=[0,48,64,96,128,192,0x100,384,512,768,1024];this.da=3E4;this.ba=80};
|
||||||
|
sjcl.prng.prototype={randomWords:function(a,b){var c=[],d;d=this.isReady(b);var e;if(d===this.u)throw new sjcl.exception.notReady("generator isn't seeded");if(d&this.J){d=!(d&this.I);e=[];var f=0,g;this.Z=e[0]=(new Date).valueOf()+this.da;for(g=0;16>g;g++)e.push(0x100000000*Math.random()|0);for(g=0;g<this.c.length&&(e=e.concat(this.c[g].finalize()),f+=this.m[g],this.m[g]=0,d||!(this.P&1<<g));g++);this.P>=1<<this.c.length&&(this.c.push(new sjcl.hash.sha256),this.m.push(0));this.f-=f;f>this.o&&(this.o=
|
||||||
|
f);this.P++;this.b=sjcl.hash.sha256.hash(this.b.concat(e));this.L=new sjcl.cipher.aes(this.b);for(d=0;4>d&&(this.h[d]=this.h[d]+1|0,!this.h[d]);d++);}for(d=0;d<a;d+=4)0===(d+1)%this.ca&&y(this),e=z(this),c.push(e[0],e[1],e[2],e[3]);y(this);return c.slice(0,a)},setDefaultParanoia:function(a,b){if(0===a&&"Setting paranoia=0 will ruin your security; use it only for testing"!==b)throw new sjcl.exception.invalid("Setting paranoia=0 will ruin your security; use it only for testing");this.M=a},addEntropy:function(a,
|
||||||
|
b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.H[c],h=this.isReady(),k=0;d=this.U[c];void 0===d&&(d=this.U[c]=this.ha++);void 0===g&&(g=this.H[c]=0);this.H[c]=(this.H[c]+1)%this.c.length;switch(typeof a){case "number":void 0===b&&(b=1);this.c[g].update([d,this.N++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if("[object Uint32Array]"===c){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else for("[object Array]"!==c&&(k=1),c=0;c<a.length&&!k;c++)"number"!==typeof a[c]&&
|
||||||
|
(k=1);if(!k){if(void 0===b)for(c=b=0;c<a.length;c++)for(e=a[c];0<e;)b++,e=e>>>1;this.c[g].update([d,this.N++,2,b,f,a.length].concat(a))}break;case "string":void 0===b&&(b=a.length);this.c[g].update([d,this.N++,3,b,f,a.length]);this.c[g].update(a);break;default:k=1}if(k)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.m[g]+=b;this.f+=b;h===this.u&&(this.isReady()!==this.u&&A("seeded",Math.max(this.o,this.f)),A("progress",this.getProgress()))},
|
||||||
|
isReady:function(a){a=this.T[void 0!==a?a:this.M];return this.o&&this.o>=a?this.m[0]>this.ba&&(new Date).valueOf()>this.Z?this.J|this.I:this.I:this.f>=a?this.J|this.u:this.u},getProgress:function(a){a=this.T[a?a:this.M];return this.o>=a?1:this.f>a?1:this.f/a},startCollectors:function(){if(!this.D){this.a={loadTimeCollector:B(this,this.ma),mouseCollector:B(this,this.oa),keyboardCollector:B(this,this.la),accelerometerCollector:B(this,this.ea),touchCollector:B(this,this.qa)};if(window.addEventListener)window.addEventListener("load",
|
||||||
|
this.a.loadTimeCollector,!1),window.addEventListener("mousemove",this.a.mouseCollector,!1),window.addEventListener("keypress",this.a.keyboardCollector,!1),window.addEventListener("devicemotion",this.a.accelerometerCollector,!1),window.addEventListener("touchmove",this.a.touchCollector,!1);else if(document.attachEvent)document.attachEvent("onload",this.a.loadTimeCollector),document.attachEvent("onmousemove",this.a.mouseCollector),document.attachEvent("keypress",this.a.keyboardCollector);else throw new sjcl.exception.bug("can't attach event");
|
||||||
|
this.D=!0}},stopCollectors:function(){this.D&&(window.removeEventListener?(window.removeEventListener("load",this.a.loadTimeCollector,!1),window.removeEventListener("mousemove",this.a.mouseCollector,!1),window.removeEventListener("keypress",this.a.keyboardCollector,!1),window.removeEventListener("devicemotion",this.a.accelerometerCollector,!1),window.removeEventListener("touchmove",this.a.touchCollector,!1)):document.detachEvent&&(document.detachEvent("onload",this.a.loadTimeCollector),document.detachEvent("onmousemove",
|
||||||
|
this.a.mouseCollector),document.detachEvent("keypress",this.a.keyboardCollector)),this.D=!1)},addEventListener:function(a,b){this.K[a][this.ga++]=b},removeEventListener:function(a,b){var c,d,e=this.K[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;c<f.length;c++)d=f[c],delete e[d]},la:function(){C(this,1)},oa:function(a){var b,c;try{b=a.x||a.clientX||a.offsetX||0,c=a.y||a.clientY||a.offsetY||0}catch(d){c=b=0}0!=b&&0!=c&&this.addEntropy([b,c],2,"mouse");C(this,0)},qa:function(a){a=
|
||||||
|
a.touches[0]||a.changedTouches[0];this.addEntropy([a.pageX||a.clientX,a.pageY||a.clientY],1,"touch");C(this,0)},ma:function(){C(this,2)},ea:function(a){a=a.accelerationIncludingGravity.x||a.accelerationIncludingGravity.y||a.accelerationIncludingGravity.z;if(window.orientation){var b=window.orientation;"number"===typeof b&&this.addEntropy(b,1,"accelerometer")}a&&this.addEntropy(a,2,"accelerometer");C(this,0)}};
|
||||||
|
function A(a,b){var c,d=sjcl.random.K[a],e=[];for(c in d)d.hasOwnProperty(c)&&e.push(d[c]);for(c=0;c<e.length;c++)e[c](b)}function C(a,b){"undefined"!==typeof window&&window.performance&&"function"===typeof window.performance.now?a.addEntropy(window.performance.now(),b,"loadtime"):a.addEntropy((new Date).valueOf(),b,"loadtime")}function y(a){a.b=z(a).concat(z(a));a.L=new sjcl.cipher.aes(a.b)}function z(a){for(var b=0;4>b&&(a.h[b]=a.h[b]+1|0,!a.h[b]);b++);return a.L.encrypt(a.h)}
|
||||||
|
function B(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6);
|
||||||
|
a:try{var D,E,F,G;if(G="undefined"!==typeof module&&module.exports){var H;try{H=require("crypto")}catch(a){H=null}G=E=H}if(G&&E.randomBytes)D=E.randomBytes(128),D=new Uint32Array((new Uint8Array(D)).buffer),sjcl.random.addEntropy(D,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){F=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(F);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(F);
|
||||||
|
else break a;sjcl.random.addEntropy(F,1024,"crypto['getRandomValues']")}}catch(a){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(a))}
|
||||||
|
sjcl.json={defaults:{v:1,iter:1E4,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},ja:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.g({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.g(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||
|
||||||
|
4<f.iv.length)throw new sjcl.exception.invalid("json encrypt: invalid parameters");"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.publicKey&&(g=a.kem(),f.kemtag=g.tag,a=g.key.slice(0,f.ks/32));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));"string"===typeof c&&(f.adata=c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.g(d,f);d.key=a;f.ct="ccm"===f.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&
|
||||||
|
b instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.encrypt(g,b,f.iv,c,f.ts):sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return f},encrypt:function(a,b,c,d){var e=sjcl.json,f=e.ja.apply(e,arguments);return e.encode(f)},ia:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.g(e.g(e.g({},e.defaults),b),c,!0);var f,g;f=b.adata;"string"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));"string"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));if(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||"string"===
|
||||||
|
typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4<b.iv.length)throw new sjcl.exception.invalid("json decrypt: invalid parameters");"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,b),a=g.key.slice(0,b.ks/32),b.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.secretKey&&(a=a.unkem(sjcl.codec.base64.toBits(b.kemtag)).slice(0,b.ks/32));"string"===typeof f&&(f=sjcl.codec.utf8String.toBits(f));g=new sjcl.cipher[b.cipher](a);f="ccm"===
|
||||||
|
b.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&b.ct instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.decrypt(g,b.ct,b.iv,b.tag,f,b.ts):sjcl.mode[b.mode].decrypt(g,b.ct,b.iv,f,b.ts);e.g(d,b);d.key=a;return 1===c.raw?f:sjcl.codec.utf8String.fromBits(f)},decrypt:function(a,b,c,d){var e=sjcl.json;return e.ia(a,e.decode(b),c,d)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new sjcl.exception.invalid("json encode: invalid property name");c+=d+'"'+
|
||||||
|
b+'":';d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:throw new sjcl.exception.bug("json encode: unsupported type");}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new sjcl.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++){if(!(d=a[c].match(/^\s*(?:(["']?)([a-z][a-z0-9]*)\1)\s*:\s*(?:(-?\d+)|"([a-z0-9+\/%*_.@=\-]*)"|(true|false))$/i)))throw new sjcl.exception.invalid("json decode: this isn't json!");
|
||||||
|
null!=d[3]?b[d[2]]=parseInt(d[3],10):null!=d[4]?b[d[2]]=d[2].match(/^(ct|adata|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4]):null!=d[5]&&(b[d[2]]="true"===d[5])}return b},g:function(a,b,c){void 0===a&&(a={});if(void 0===b)return a;for(var d in b)if(b.hasOwnProperty(d)){if(c&&void 0!==a[d]&&a[d]!==b[d])throw new sjcl.exception.invalid("required parameter overridden");a[d]=b[d]}return a},sa:function(a,b){var c={},d;for(d in a)a.hasOwnProperty(d)&&a[d]!==b[d]&&(c[d]=a[d]);return c},ra:function(a,
|
||||||
|
b){var c={},d;for(d=0;d<b.length;d++)void 0!==a[b[d]]&&(c[b[d]]=a[b[d]]);return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.pa={};sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.pa,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=void 0===b.salt?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
|
||||||
|
"undefined"!==typeof module&&module.exports&&(module.exports=sjcl);"function"===typeof define&&define([],function(){return sjcl});
|
39
chatto/src/main/resources/templates/chat.html
Normal file
39
chatto/src/main/resources/templates/chat.html
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<div th:replace="fragments/head :: headFragment">
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title id="pageTitle">Chat</title>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <script th:src="@{js/my_Crypto.js}" type="text/javascript"></script> -->
|
||||||
|
<link th:href="@{/css/master.css}" href="../static/css/master.css" rel="stylesheet">
|
||||||
|
</link>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<textarea id="chatTextArea" cols="80" rows="20" disabled></textarea>
|
||||||
|
<!-- <form action="#" th:action="@{/seedstartermng}" th:object="${seedStarter}" method="post"> -->
|
||||||
|
<!-- th:action="@{/api/chat}" -->
|
||||||
|
<form action="#" th:object="${chatMessageDTO}" method="post" id="chatMessageForm">
|
||||||
|
<label for="toUser">User to send to: </label>
|
||||||
|
<th:block th:each="userName: ${userNames}">
|
||||||
|
<input type="radio" th:field="*{toUser}" th:value="${userName}">
|
||||||
|
<label th:for="${#ids.prev('toUser')}" th:text="${userName}">DemoUser</label>
|
||||||
|
</th:block> <br>
|
||||||
|
<label for="chatInput">Your message: </label>
|
||||||
|
<input type="text" id="chatInput"> <br>
|
||||||
|
<label for="passphrase">Passphrase: </label>
|
||||||
|
<input type="password" id="passphrase">
|
||||||
|
<input type="submit" value="Send">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script th:src="@{js/chat.js}" type="text/javascript"></script>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
<!-- <div th:include="::frag (${value1},${value2})">...</div>
|
||||||
|
<div th:include="::frag (onevar=${value1},twovar=${value2})">...</div> -->
|
18
chatto/src/main/resources/templates/crypto.html
Normal file
18
chatto/src/main/resources/templates/crypto.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<title></title>
|
||||||
|
<!--
|
||||||
|
<link th:href="@{/css/things.css}" rel="stylesheet"></link>
|
||||||
|
JS
|
||||||
|
<script th:src="@{/js/things.js}" type="text/javascript"></script> -->
|
||||||
|
<script th:src="@{js/scljs.js}" type="text/javascript"></script>
|
||||||
|
<script th:src="@{js/my_Crypto.js}" type="text/javascript"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="crypt"></div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
23
chatto/src/main/resources/templates/fragments/head.html
Normal file
23
chatto/src/main/resources/templates/fragments/head.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<th:block th:fragment="headFragment">
|
||||||
|
<script th:src="@{js/scljs.js}" type="text/javascript"></script>
|
||||||
|
<!--<script th:src="@{js/my_Crypto.js}" type="text/javascript"></script>-->
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.css" rel="stylesheet"
|
||||||
|
type="text/css">
|
||||||
|
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/sprintf/1.1.2/sprintf.min.js" type="text/javascript"></script>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<!-- <title th:text="${title}">Page</title> -->
|
||||||
|
<title th:include=":: #pageTitle">Layout Generic Title</title>
|
||||||
|
</th:block>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
<!-- th:href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.css"-->
|
@ -1,17 +1,24 @@
|
|||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html xmlns:th="http://www.thymeleaf.org">
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
<head>
|
|
||||||
<title>Title</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div>Login Page</div>
|
|
||||||
|
|
||||||
<!-- <form action="#" th:action="@{/greeting}" th:object="${greeting}" method="post">
|
<head>
|
||||||
|
<div th:replace="fragments/head :: headFragment">
|
||||||
|
<title id="pageTitle">Login</title>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="body-container" class="shadow-sm p-3 mb-5 bg-white rounded">
|
||||||
|
<!-- <div>Login Page</div> -->
|
||||||
|
<form action="#" th:action="@{/login}" method="POST" id="loginForm">
|
||||||
|
<fieldset>
|
||||||
|
<!-- <form action="#" th:action="@{/greeting}" th:object="${greeting}" method="post">
|
||||||
<p>Id: <input type="text" th:field="*{id}" /></p>
|
<p>Id: <input type="text" th:field="*{id}" /></p>
|
||||||
<p>Message: <input type="text" th:field="*{content}" /></p>
|
<p>Message: <input type="text" th:field="*{content}" /></p>
|
||||||
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
|
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
|
||||||
</form> -->
|
</form> -->
|
||||||
<!-- <form action="#" th:action="@{/perform_login}" th:object=${user} method="POST">
|
<!-- <form action="#" th:action="@{/perform_login}" th:object=${user} method="POST">
|
||||||
<label>Enter user name: </label>
|
<label>Enter user name: </label>
|
||||||
<input th:field="*{userName}" type="text" name="username" id="username">
|
<input th:field="*{userName}" type="text" name="username" id="username">
|
||||||
<br> <br> <label>Enter password: </label>
|
<br> <br> <label>Enter password: </label>
|
||||||
@ -19,12 +26,26 @@
|
|||||||
<input type="submit" value="Submit">
|
<input type="submit" value="Submit">
|
||||||
</form>
|
</form>
|
||||||
-->
|
-->
|
||||||
<form action="#" th:action="@{/perform_login}" method="POST">
|
<legend>Please Login</legend>
|
||||||
<label>Enter user name: </label>
|
<div th:if="${param.error}" class="alert alert-error">
|
||||||
<input type="text" name="username" id="username">
|
Invalid username or password.
|
||||||
<br> <br> <label>Enter password: </label>
|
</div>
|
||||||
<input type="password" name="password" id="username"> <br> <br>
|
<div th:if="${param.logout}" class="alert alert-success">
|
||||||
<input type="submit" value="Submit">
|
You have been logged out.
|
||||||
</form>
|
</div>
|
||||||
|
|
||||||
|
<label for="username">Enter user name: </label>
|
||||||
|
<input type="text" name="username" id="username">
|
||||||
|
<br> <br>
|
||||||
|
<label for="password">Enter password: </label>
|
||||||
|
<input type="password" name="password" id="password">
|
||||||
|
<br> <br>
|
||||||
|
<button type="submit" class="btn btn-primary">Login</button>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<script src="../js/loginPage.js" type="text/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -11,6 +11,7 @@
|
|||||||
type="text" name="username" id="username"> <br> <br>
|
type="text" name="username" id="username"> <br> <br>
|
||||||
<label>Enter password: </label> <input th:field="*{password}"
|
<label>Enter password: </label> <input th:field="*{password}"
|
||||||
type="password" name="password" id="password"> <br> <br>
|
type="password" name="password" id="password"> <br> <br>
|
||||||
|
<input type="password" id="password-repeat">
|
||||||
<input type="submit" value="Submit">
|
<input type="submit" value="Submit">
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
|
12
chatto/src/main/resources/templates/restLogout.html
Normal file
12
chatto/src/main/resources/templates/restLogout.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Insert title here</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form action="#" th:action="@{/api/perform_logout}" method="POST">
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -52,19 +52,16 @@ public class ChattoApplicationTests {
|
|||||||
// chatMessageRepository.save(chatMessage);
|
// chatMessageRepository.save(chatMessage);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@Test
|
/*
|
||||||
public void testSave() {
|
* @Test public void testSave() { ChatUser fromUser = new ChatUser(); fromUser =
|
||||||
ChatUser fromUser = new ChatUser();
|
* userRepository.findByUserName("hmm"); ChatUser toUser = new ChatUser();
|
||||||
fromUser = userRepository.findByUserName("hmm");
|
* toUser = userRepository.findByUserName("user2"); ChatMessage chatMessage =
|
||||||
ChatUser toUser = new ChatUser();
|
* new ChatMessage(); chatMessage.setMessage("Hello!");
|
||||||
toUser = userRepository.findByUserName("user2");
|
* chatMessage.setFromUser(fromUser); chatMessage.setToUser(toUser);
|
||||||
ChatMessage chatMessage = new ChatMessage();
|
*
|
||||||
chatMessage.setMessage("Hello!");
|
* // chatMessageRepository.save(chatMessage);
|
||||||
chatMessage.setFromUser(fromUser);
|
* when(mockChatMessageRepository.save(any(ChatMessage.class))).thenReturn(
|
||||||
chatMessage.setToUser(toUser);
|
* chatMessage); verify(mockChatMessageRepository,
|
||||||
|
* times(1)).save(Mockito.any(ChatMessage.class)); }
|
||||||
// chatMessageRepository.save(chatMessage);
|
*/
|
||||||
when(mockChatMessageRepository.save(any(ChatMessage.class))).thenReturn(chatMessage);
|
|
||||||
verify(mockChatMessageRepository, times(1)).save(Mockito.any(ChatMessage.class));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user