Compare commits
42 Commits
sonali
...
e1da884fbb
| Author | SHA1 | Date | |
|---|---|---|---|
|
e1da884fbb
|
|||
|
490578cfe2
|
|||
|
c45bc27c81
|
|||
|
95d77fb3fe
|
|||
|
92b335410b
|
|||
|
b7ce85a5ec
|
|||
|
7ae2eca31b
|
|||
|
0aba0e7911
|
|||
|
7411f8b4fa
|
|||
| b2147537ca | |||
| 063bfa794a | |||
|
2622667de4
|
|||
| dd958b0fde | |||
|
4e028dd971
|
|||
|
a6325d5681
|
|||
|
c5ff741f8c
|
|||
|
3920ec7fbd
|
|||
|
4af5aabd42
|
|||
|
23eda639c0
|
|||
|
f06dbd84ad
|
|||
|
0661b2540f
|
|||
|
222fd796f2
|
|||
|
7f6b2eb344
|
|||
|
88fd49c807
|
|||
|
12355f25c7
|
|||
|
9cb9c67b09
|
|||
|
31f13b980b
|
|||
|
2379d95759
|
|||
|
178a32f908
|
|||
|
218ccb720f
|
|||
|
dd52421392
|
|||
|
aaf5d2dbd8
|
|||
|
4b21828510
|
|||
|
e14f27830e
|
|||
|
04f291910f
|
|||
|
c88cb5ac0e
|
|||
|
c133617990
|
|||
|
a9e7d23c3c
|
|||
|
91e0d50c0a
|
|||
|
39aa31625d
|
|||
|
8ae2ced645
|
|||
|
d3e1aff0fb
|
@@ -1,3 +1,5 @@
|
|||||||
|
src/main/resources/application.properties.bak
|
||||||
|
wiki/
|
||||||
HELP.md
|
HELP.md
|
||||||
target/
|
target/
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
|||||||
+5
-4
@@ -5,7 +5,7 @@ FROM debian:12-slim
|
|||||||
|
|
||||||
# Metadata
|
# Metadata
|
||||||
LABEL maintainer="kshitijka"
|
LABEL maintainer="kshitijka"
|
||||||
LABEL version=1.0
|
LABEL version=1.5
|
||||||
LABEL description="Skycrate is a web based file management system that uses Hadoop as filesystem."
|
LABEL description="Skycrate is a web based file management system that uses Hadoop as filesystem."
|
||||||
|
|
||||||
# Update & upgrade & install & rm
|
# Update & upgrade & install & rm
|
||||||
@@ -19,12 +19,13 @@ RUN useradd -s /bin/bash skycrateBack
|
|||||||
# Create work dir
|
# Create work dir
|
||||||
RUN mkdir /app
|
RUN mkdir /app
|
||||||
RUN chown -R skycrateBack:skycrateBack /app
|
RUN chown -R skycrateBack:skycrateBack /app
|
||||||
COPY ./target/ /app
|
COPY ./target/skycrateBackend-0.0.3.jar /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Switch user
|
# Switch user
|
||||||
USER skycrateBack
|
USER skycrateBack
|
||||||
|
|
||||||
EXPOSE 8081
|
# Expose port for backend
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
CMD ["java", "-jar", "/app/skycrateBackend-0.0.1-SNAPSHOT.jar"]
|
CMD ["java", "-jar", "skycrateBackend-0.0.3.jar"]
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Skycrate-Backend
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This repository holds code for [Skycrate](https://git.kska.io/notkshitij/Skycrate) backend.
|
||||||
|
|
||||||
|
---
|
||||||
@@ -1,180 +1,164 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
<modelVersion>4.0.0</modelVersion>
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
|
||||||
<version>3.4.4</version>
|
|
||||||
<relativePath/> <!-- lookup parent from repository -->
|
|
||||||
</parent>
|
|
||||||
<groupId>com.skycrate.backend</groupId>
|
|
||||||
<artifactId>skycrateBackend</artifactId>
|
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
|
||||||
<name>skycrateBackend</name>
|
|
||||||
<description>Cloud Storage App using HDFS</description>
|
|
||||||
<url/>
|
|
||||||
<licenses>
|
|
||||||
<license/>
|
|
||||||
</licenses>
|
|
||||||
<developers>
|
|
||||||
<developer/>
|
|
||||||
</developers>
|
|
||||||
<scm>
|
|
||||||
<connection/>
|
|
||||||
<developerConnection/>
|
|
||||||
<tag/>
|
|
||||||
<url/>
|
|
||||||
</scm>
|
|
||||||
<properties>
|
|
||||||
<java.version>17</java.version>
|
|
||||||
</properties>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<parent>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<optional>true</optional>
|
<version>3.4.4</version>
|
||||||
</dependency>
|
<relativePath/>
|
||||||
<dependency>
|
</parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
|
<groupId>com.skycrate.backend</groupId>
|
||||||
|
<artifactId>skycrateBackend</artifactId>
|
||||||
|
<version>0.0.3</version>
|
||||||
|
<name>skycrateBackend</name>
|
||||||
|
<description>Cloud Storage App using HDFS</description>
|
||||||
|
|
||||||
<!-- NEWLY ADDED DEPENDECIES-->
|
<properties>
|
||||||
<!-- Spring Boot Web -->
|
<java.version>17</java.version>
|
||||||
<dependency>
|
</properties>
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
<version>3.2.4</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Spring Boot Security -->
|
<dependencies>
|
||||||
<dependency>
|
<!-- Spring Boot Starters -->
|
||||||
<groupId>org.springframework.boot</groupId>
|
<dependency>
|
||||||
<artifactId>spring-boot-starter-security</artifactId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<version>3.2.4</version>
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring Boot Data JPA -->
|
<!-- MySQL JDBC -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>com.mysql</groupId>
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
<artifactId>mysql-connector-j</artifactId>
|
||||||
<version>3.2.4</version>
|
<version>8.3.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- MySQL Driver -->
|
<!-- JWT -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mysql</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>mysql-connector-j</artifactId>
|
<artifactId>jjwt-api</artifactId>
|
||||||
<version>8.3.0</version>
|
<version>0.11.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-impl</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-jackson</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring Boot Validation -->
|
<!-- Hadoop HDFS -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.apache.hadoop</groupId>
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
<artifactId>hadoop-common</artifactId>
|
||||||
<version>3.2.4</version>
|
<version>3.4.1</version>
|
||||||
</dependency>
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hadoop</groupId>
|
||||||
|
<artifactId>hadoop-hdfs</artifactId>
|
||||||
|
<version>3.4.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hadoop</groupId>
|
||||||
|
<artifactId>hadoop-client</artifactId>
|
||||||
|
<version>3.4.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- JSON Web Token (JWT) -->
|
<!-- Commons IO -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>commons-io</groupId>
|
||||||
<artifactId>jjwt-api</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
<version>0.11.5</version>
|
<version>2.11.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-impl</artifactId>
|
|
||||||
<version>0.11.5</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-jackson</artifactId>
|
|
||||||
<version>0.11.5</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Hadoop Dependencies -->
|
<!-- Caffeine Cache -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.hadoop</groupId>
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
<artifactId>hadoop-common</artifactId>
|
<artifactId>caffeine</artifactId>
|
||||||
<version>3.4.1</version>
|
<version>3.1.8</version>
|
||||||
<exclusions>
|
</dependency>
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<!-- Lombok -->
|
||||||
<groupId>org.apache.hadoop</groupId>
|
<dependency>
|
||||||
<artifactId>hadoop-hdfs</artifactId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<version>3.4.1</version>
|
<artifactId>lombok</artifactId>
|
||||||
</dependency>
|
<version>1.18.30</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<!-- Testing -->
|
||||||
<groupId>org.apache.hadoop</groupId>
|
<dependency>
|
||||||
<artifactId>hadoop-client</artifactId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<version>3.4.1</version>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
</dependency>
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Logging (SLF4J + Logback) -->
|
<!-- Caching -->
|
||||||
<!-- <dependency>-->
|
<dependency>
|
||||||
<!-- <groupId>org.slf4j</groupId>-->
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
<!-- <artifactId>slf4j-api</artifactId>-->
|
<artifactId>caffeine</artifactId>
|
||||||
<!-- <version>1.7.36</version>-->
|
<version>3.0.5</version>
|
||||||
<!-- </dependency>-->
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-cache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<!-- <dependency>-->
|
<build>
|
||||||
<!-- <groupId>ch.qos.logback</groupId>-->
|
<plugins>
|
||||||
<!-- <artifactId>logback-classic</artifactId>-->
|
<!-- Compiler Plugin -->
|
||||||
<!-- <version>1.2.11</version>-->
|
<plugin>
|
||||||
<!-- </dependency>-->
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<!-- Apache Commons IO (for file operations) -->
|
<version>3.11.0</version>
|
||||||
<dependency>
|
<configuration>
|
||||||
<groupId>commons-io</groupId>
|
<source>${java.version}</source>
|
||||||
<artifactId>commons-io</artifactId>
|
<target>${java.version}</target>
|
||||||
<version>2.11.0</version>
|
<annotationProcessorPaths>
|
||||||
</dependency>
|
<path>
|
||||||
</dependencies>
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
<build>
|
<version>1.18.30</version>
|
||||||
<plugins>
|
</path>
|
||||||
<plugin>
|
</annotationProcessorPaths>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
</configuration>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
</plugin>
|
||||||
<configuration>
|
|
||||||
<annotationProcessorPaths>
|
|
||||||
<path>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
</path>
|
|
||||||
</annotationProcessorPaths>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<excludes>
|
|
||||||
<exclude>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
</exclude>
|
|
||||||
</excludes>
|
|
||||||
</configuration>
|
|
||||||
|
|
||||||
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
|
<!-- Spring Boot Plugin -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
+28
-20
@@ -1,7 +1,5 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.config;
|
package com.skycrate.backend.skycrateBackend.config;
|
||||||
|
|
||||||
import java.security.AuthProvider;
|
|
||||||
|
|
||||||
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.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
@@ -10,38 +8,48 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider
|
|||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.security.crypto.bcrypt.BCrypt;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
|
|
||||||
|
// Application-wide security configuration.
|
||||||
|
// Configures user authentication, password encoding, and authentication provider.
|
||||||
@Configuration
|
@Configuration
|
||||||
public class ApplicationConfiguration {
|
public class ApplicationConfiguration {
|
||||||
|
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
public ApplicationConfiguration(UserRepository userRepository){
|
|
||||||
this.userRepository=userRepository;
|
|
||||||
|
|
||||||
|
public ApplicationConfiguration(UserRepository userRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Custom UserDetailsService to fetch user details by email.
|
||||||
@Bean
|
@Bean
|
||||||
UserDetailsService userDetailsService() {
|
public UserDetailsService userDetailsService() {
|
||||||
return username -> userRepository.findByEmail(username)
|
return username -> userRepository.findByEmail(username)
|
||||||
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
.orElseThrow(() -> new UsernameNotFoundException("User not found with email: " + username));
|
||||||
}
|
|
||||||
@Bean
|
|
||||||
BCryptPasswordEncoder passwordEncoder(){
|
|
||||||
return new BCryptPasswordEncoder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BCrypt password encoder with a higher strength for better security.
|
||||||
|
// Cost factor 12 is considered a good balance for production use.
|
||||||
@Bean
|
@Bean
|
||||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception{
|
public PasswordEncoder passwordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthenticationProvider using DAO with custom user service and password encoder.
|
||||||
|
@Bean
|
||||||
|
public AuthenticationProvider authenticationProvider() {
|
||||||
|
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
|
||||||
|
authProvider.setUserDetailsService(userDetailsService());
|
||||||
|
authProvider.setPasswordEncoder(passwordEncoder());
|
||||||
|
return authProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provides the AuthenticationManager for authenticating credentials.
|
||||||
|
@Bean
|
||||||
|
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
|
||||||
return config.getAuthenticationManager();
|
return config.getAuthenticationManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
AuthenticationProvider authenticationProvider(){
|
|
||||||
DaoAuthenticationProvider authprovider=new DaoAuthenticationProvider();
|
|
||||||
authprovider.setUserDetailsService(userDetailsService());
|
|
||||||
authprovider.setPasswordEncoder(passwordEncoder());
|
|
||||||
return authprovider;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.config;
|
||||||
|
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableCaching
|
||||||
|
public class CacheConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CaffeineCacheManager cacheManager() {
|
||||||
|
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
|
||||||
|
cacheManager.setCaffeine(Caffeine.newBuilder()
|
||||||
|
.expireAfterWrite(30, TimeUnit.MINUTES) // Cache expiry time
|
||||||
|
.maximumSize(100)); // Maximum cache size
|
||||||
|
return cacheManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.config;
|
package com.skycrate.backend.skycrateBackend.config;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration; // Hadoop Configuration
|
||||||
import org.apache.hadoop.fs.FileSystem;
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -8,13 +8,32 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
|
|
||||||
|
@org.springframework.context.annotation.Configuration
|
||||||
public class HDFSConfig {
|
public class HDFSConfig {
|
||||||
public static FileSystem getHDFS() throws Exception {
|
|
||||||
Configuration conf = new Configuration();
|
private static final String HDFS_URI = System.getenv("HDFS_URI"); // e.g., hdfs://namenode:9000
|
||||||
conf.set("fs.defaultFS", "hdfs://namenode:9000");
|
private static final String HDFS_USER = System.getenv("HDFS_USER"); // e.g., hdfsuser
|
||||||
return FileSystem.get(new URI("hdfs://namenode:9000"), conf);
|
|
||||||
|
@Bean
|
||||||
|
public FileSystem fileSystem() throws Exception {
|
||||||
|
return getHDFS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FileSystem getHDFS() throws Exception {
|
||||||
|
if (HDFS_URI == null || HDFS_URI.isBlank()) {
|
||||||
|
throw new IllegalStateException("HDFS_URI environment variable not set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration conf = new Configuration();
|
||||||
|
conf.set("fs.defaultFS", HDFS_URI);
|
||||||
|
|
||||||
|
if (HDFS_USER != null && !HDFS_USER.isBlank()) {
|
||||||
|
return UserGroupInformation.createRemoteUser(HDFS_USER)
|
||||||
|
.doAs((PrivilegedExceptionAction<FileSystem>) () ->
|
||||||
|
FileSystem.get(new URI(HDFS_URI), conf)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return FileSystem.get(new URI(HDFS_URI), conf);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.config;
|
||||||
|
|
||||||
|
import org.apache.catalina.connector.Connector;
|
||||||
|
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||||
|
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class HttpToHttpsRedirectConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> containerCustomizer() {
|
||||||
|
return factory -> {
|
||||||
|
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
|
||||||
|
connector.setScheme("http");
|
||||||
|
connector.setPort(8085); // HTTP port
|
||||||
|
connector.setSecure(false);
|
||||||
|
connector.setRedirectPort(8443); // HTTPS port
|
||||||
|
factory.addAdditionalTomcatConnectors(connector);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
-74
@@ -1,74 +0,0 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.config;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
||||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
|
||||||
|
|
||||||
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
|
||||||
|
|
||||||
import jakarta.servlet.FilterChain;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|
||||||
|
|
||||||
|
|
||||||
private final HandlerExceptionResolver handlerExceptionResolver;
|
|
||||||
private JwtService jwtService;
|
|
||||||
private UserDetailsService userDetailsService;
|
|
||||||
|
|
||||||
public JwtAuthenticationFilter(JwtService jwtService,UserDetailsService userDetailsService,HandlerExceptionResolver handlerExceptionResolver){
|
|
||||||
|
|
||||||
this.handlerExceptionResolver=handlerExceptionResolver;
|
|
||||||
this.jwtService=jwtService;
|
|
||||||
this.userDetailsService=userDetailsService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(
|
|
||||||
@NonNull HttpServletRequest request,
|
|
||||||
@NonNull HttpServletResponse response,
|
|
||||||
@NonNull FilterChain filterChain) throws ServletException, IOException {
|
|
||||||
final String authHeader=request.getHeader("Authorization");
|
|
||||||
if (authHeader==null || !authHeader.startsWith("Bearer")){
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
final String userjwt=authHeader.substring(7);
|
|
||||||
final String userEmail=jwtService.extractUsername(userjwt);
|
|
||||||
Authentication authentication=SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
if(userEmail!=null && authentication==null){
|
|
||||||
|
|
||||||
UserDetails userDetails=this.userDetailsService.loadUserByUsername(userEmail);
|
|
||||||
if (jwtService.isTokenValid(userjwt, userDetails)) {
|
|
||||||
|
|
||||||
UsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(
|
|
||||||
userDetails, null, userDetails.getAuthorities()
|
|
||||||
);
|
|
||||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
catch (Exception err) {
|
|
||||||
handlerExceptionResolver.resolveException(request, response, null, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,23 +1,52 @@
|
|||||||
// package com.skycrate.backend.skycrateBackend.config;
|
package com.skycrate.backend.skycrateBackend.config;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.security.JwtAuthenticationFilter;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
|
||||||
// import org.springframework.context.annotation.Bean;
|
@Configuration
|
||||||
// import org.springframework.context.annotation.Configuration;
|
public class SecurityConfig {
|
||||||
// import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
// import org.springframework.security.web.SecurityFilterChain;
|
|
||||||
|
|
||||||
// @Configuration
|
private final AuthenticationProvider authenticationProvider;
|
||||||
// public class SecurityConfig {
|
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||||
|
|
||||||
// @Bean
|
public SecurityConfig(AuthenticationProvider authenticationProvider,
|
||||||
// public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
JwtAuthenticationFilter jwtAuthenticationFilter) {
|
||||||
// http
|
this.authenticationProvider = authenticationProvider;
|
||||||
// .csrf(csrf -> csrf.disable()) // Disable CSRF for testing APIs
|
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
|
||||||
// .authorizeHttpRequests(auth -> auth
|
}
|
||||||
// .requestMatchers("/api/hdfs/**").permitAll() // Allow HDFS endpoints
|
|
||||||
// .anyRequest().authenticated() // Everything else needs auth
|
|
||||||
// );
|
|
||||||
|
|
||||||
// return http.build();
|
@Bean
|
||||||
// }
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
// }
|
http
|
||||||
|
.csrf(csrf -> csrf.disable())
|
||||||
|
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
|
.authenticationProvider(authenticationProvider)
|
||||||
|
.authorizeHttpRequests(auth -> auth
|
||||||
|
.requestMatchers("/api/auth/logout","/api/auth/login", "/api/auth/register", "/actuator/**").permitAll()
|
||||||
|
.requestMatchers(HttpMethod.GET, "/public/**").permitAll()
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
)
|
||||||
|
.requiresChannel(channel -> channel
|
||||||
|
.anyRequest().requiresSecure()
|
||||||
|
)
|
||||||
|
.headers(headers -> headers
|
||||||
|
.httpStrictTransportSecurity(hsts -> hsts
|
||||||
|
.includeSubDomains(true)
|
||||||
|
.maxAgeInSeconds(31536000)
|
||||||
|
)
|
||||||
|
// Spring Security 6+ no longer supports xss.block(true), so we just enable or disable it.
|
||||||
|
.xssProtection(xss -> xss.disable())
|
||||||
|
.frameOptions(frame -> frame.deny())
|
||||||
|
)
|
||||||
|
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
|
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
|
||||||
import org.springframework.web.cors.CorsConfigurationSource;
|
|
||||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
|
||||||
public class SecurityConfiguration {
|
|
||||||
private final AuthenticationProvider authenticationProvider;
|
|
||||||
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
|
||||||
|
|
||||||
public SecurityConfiguration(
|
|
||||||
JwtAuthenticationFilter jwtAuthenticationFilter,
|
|
||||||
AuthenticationProvider authenticationProvider
|
|
||||||
) {
|
|
||||||
this.authenticationProvider = authenticationProvider;
|
|
||||||
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Bean
|
|
||||||
// public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
||||||
// http.csrf()
|
|
||||||
// .disable()
|
|
||||||
// .authorizeHttpRequests()
|
|
||||||
// .requestMatchers("/api/hdfs/**") // Specific API endpoints that don't require authentication
|
|
||||||
// .permitAll()
|
|
||||||
// .requestMatchers("/api/**") // Other endpoints that should be open
|
|
||||||
// .permitAll()
|
|
||||||
// .anyRequest()
|
|
||||||
// .authenticated() // All other requests require authentication
|
|
||||||
// .and()
|
|
||||||
// .sessionManagement()
|
|
||||||
// .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
|
||||||
// .and()
|
|
||||||
// .authenticationProvider(authenticationProvider)
|
|
||||||
// .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
|
||||||
//
|
|
||||||
// return http.build();
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
||||||
return http
|
|
||||||
.securityMatcher("/**")
|
|
||||||
.authorizeHttpRequests(auth -> auth
|
|
||||||
.requestMatchers("/api/hdfs/**", "/api/**").permitAll()
|
|
||||||
.anyRequest().authenticated()
|
|
||||||
)
|
|
||||||
.sessionManagement(session -> session
|
|
||||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
|
||||||
)
|
|
||||||
.authenticationProvider(authenticationProvider)
|
|
||||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
|
|
||||||
.csrf(csrf -> csrf.disable())
|
|
||||||
.cors(cors -> {}) // 🔥 This line enables CORS and connects to your CorsConfigurationSource bean
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// @Bean
|
|
||||||
// CorsConfigurationSource corsConfigurationSource() {
|
|
||||||
// CorsConfiguration configuration = new CorsConfiguration();
|
|
||||||
//
|
|
||||||
// configuration.setAllowedOrigins(List.of("*"));
|
|
||||||
// configuration.setAllowedMethods(List.of("GET", "PUT", "DELETE", "POST"));
|
|
||||||
// configuration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
|
|
||||||
//
|
|
||||||
// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
|
||||||
//
|
|
||||||
// source.registerCorsConfiguration("/**", configuration);
|
|
||||||
//
|
|
||||||
// return source;
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
CorsConfigurationSource corsConfigurationSource() {
|
|
||||||
CorsConfiguration configuration = new CorsConfiguration();
|
|
||||||
|
|
||||||
// 🔥 Allow all origins (wildcard) safely with credentials
|
|
||||||
configuration.setAllowedOriginPatterns(List.of("*"));
|
|
||||||
|
|
||||||
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
|
||||||
configuration.setAllowedHeaders(List.of("*"));
|
|
||||||
configuration.setExposedHeaders(List.of("Authorization"));
|
|
||||||
configuration.setAllowCredentials(true); // Needed for cookies / Authorization headers
|
|
||||||
|
|
||||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
|
||||||
source.registerCorsConfiguration("/**", configuration);
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
+108
-32
@@ -1,58 +1,134 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.controller;
|
package com.skycrate.backend.skycrateBackend.controller;
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import com.skycrate.backend.skycrateBackend.dto.LoginRequest;
|
||||||
|
import com.skycrate.backend.skycrateBackend.dto.LoginResponse;
|
||||||
import com.skycrate.backend.skycrateBackend.dto.LoginUserDto;
|
|
||||||
import com.skycrate.backend.skycrateBackend.dto.RegisterUserDto;
|
import com.skycrate.backend.skycrateBackend.dto.RegisterUserDto;
|
||||||
import com.skycrate.backend.skycrateBackend.models.User;
|
import com.skycrate.backend.skycrateBackend.dto.TokenRefreshRequest;
|
||||||
import com.skycrate.backend.skycrateBackend.responses.LoginResponse;
|
import com.skycrate.backend.skycrateBackend.dto.TokenRefreshResponse;
|
||||||
import com.skycrate.backend.skycrateBackend.services.AuthenticationService;
|
import com.skycrate.backend.skycrateBackend.entity.RefreshToken;
|
||||||
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import com.skycrate.backend.skycrateBackend.security.TokenBlacklistService;
|
||||||
|
import com.skycrate.backend.skycrateBackend.services.*;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
|
|
||||||
|
|
||||||
@RequestMapping("/api")
|
|
||||||
@RestController
|
@RestController
|
||||||
|
@RequestMapping("/api/auth")
|
||||||
public class AuthController {
|
public class AuthController {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FileService.class);
|
||||||
|
private final AuthenticationManager authManager;
|
||||||
private final JwtService jwtService;
|
private final JwtService jwtService;
|
||||||
private AuthenticationService authenticationService;
|
private final UserRepository userRepository;
|
||||||
|
private final RefreshTokenService refreshTokenService;
|
||||||
|
private final TokenBlacklistService tokenBlacklistService;
|
||||||
|
private final RateLimiterService rateLimiterService;
|
||||||
|
private final AuthenticationService authenticationService;
|
||||||
|
|
||||||
public AuthController(JwtService jwtService,AuthenticationService authenticationService){
|
public AuthController(
|
||||||
this.jwtService=jwtService;
|
AuthenticationManager authManager,
|
||||||
this.authenticationService=authenticationService;
|
JwtService jwtService,
|
||||||
|
UserRepository userRepository,
|
||||||
|
RefreshTokenService refreshTokenService,
|
||||||
|
TokenBlacklistService tokenBlacklistService,
|
||||||
|
RateLimiterService rateLimiterService,
|
||||||
|
AuthenticationService authenticationService
|
||||||
|
) {
|
||||||
|
this.authManager = authManager;
|
||||||
|
this.jwtService = jwtService;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.refreshTokenService = refreshTokenService;
|
||||||
|
this.tokenBlacklistService = tokenBlacklistService;
|
||||||
|
this.rateLimiterService = rateLimiterService;
|
||||||
|
this.authenticationService = authenticationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/test")
|
// New Register Endpoint
|
||||||
public String teString(@RequestParam String param) {
|
@PostMapping("/register")
|
||||||
return new String();
|
public ResponseEntity<?> register(@RequestBody RegisterUserDto request) {
|
||||||
|
User user = authenticationService.signUp(request);
|
||||||
|
return ResponseEntity.ok("User registered successfully with username: " + user.getUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public ResponseEntity<LoginResponse> LoginController(@RequestBody LoginUserDto entity) {
|
public ResponseEntity<?> login(@RequestBody LoginRequest request, HttpServletRequest servletRequest) {
|
||||||
|
String ip = servletRequest.getRemoteAddr();
|
||||||
|
|
||||||
User authenticatedUser=authenticationService.authenticate(entity);
|
if (rateLimiterService.isBlocked(ip)) {
|
||||||
String jwtToken=jwtService.generateToken(authenticatedUser);
|
return ResponseEntity.status(429).body("Too many login attempts. Please try again later.");
|
||||||
|
}
|
||||||
|
|
||||||
LoginResponse loginResponse=new LoginResponse().setToken(jwtToken).setExpiresIn(jwtService.getExpirtationTime());
|
try {
|
||||||
return ResponseEntity.ok(loginResponse);
|
authManager.authenticate(
|
||||||
|
new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword())
|
||||||
|
);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
rateLimiterService.recordFailedAttempt(ip);
|
||||||
|
return ResponseEntity.status(401).body("Invalid credentials.");
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = userRepository.findByEmail(request.getEmail())
|
||||||
|
.orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
|
|
||||||
|
rateLimiterService.resetAttempts(ip);
|
||||||
|
|
||||||
|
String accessToken = jwtService.generateToken(user);
|
||||||
|
RefreshToken refreshToken = refreshTokenService.createRefreshToken(user);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(new LoginResponse(accessToken, refreshToken.getToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/signup")
|
@PostMapping("/logout")
|
||||||
public ResponseEntity<User> register(@RequestBody RegisterUserDto entity) {
|
public ResponseEntity<?> logout(HttpServletRequest request) {
|
||||||
User registeredUser=authenticationService.signUp(entity);
|
String authHeader = request.getHeader("Authorization");
|
||||||
|
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||||
|
return ResponseEntity.badRequest().body("Missing or invalid Authorization header");
|
||||||
|
}
|
||||||
|
|
||||||
|
String token = authHeader.substring(7);
|
||||||
|
String username = jwtService.extractUsername(token);
|
||||||
|
|
||||||
return ResponseEntity.ok(registeredUser);
|
userRepository.findByUsername(username).ifPresent(user -> {
|
||||||
|
// Clear the cached decrypted private key for the user
|
||||||
|
authenticationService.clearDecryptedPrivateKeyCache(user.getId().toString());
|
||||||
|
|
||||||
|
// Delete the refresh token associated with the user
|
||||||
|
refreshTokenService.logout(user); // This should delete the token
|
||||||
|
});
|
||||||
|
|
||||||
|
tokenBlacklistService.blacklistToken(token);
|
||||||
|
|
||||||
|
return ResponseEntity.ok("Logged out successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/refresh")
|
||||||
|
public ResponseEntity<?> refresh(@RequestBody TokenRefreshRequest request) {
|
||||||
|
String requestToken = request.getRefreshToken();
|
||||||
|
log.error("Received refresh token: " + requestToken);
|
||||||
|
|
||||||
|
return refreshTokenService.findByToken(requestToken)
|
||||||
|
.map(token -> {
|
||||||
|
if (refreshTokenService.isExpired(token)) {
|
||||||
|
log.error("Refresh token expired for user: " + token.getUser().getUsername());
|
||||||
|
// Clear the cached key on token expiry
|
||||||
|
authenticationService.clearDecryptedPrivateKeyCache(token.getUser().getId().toString());
|
||||||
|
return ResponseEntity.status(403).body("Refresh token expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = token.getUser();
|
||||||
|
String newAccessToken = jwtService.generateToken(user);
|
||||||
|
log.info("Generated new access token for user: " + user.getUsername());
|
||||||
|
return ResponseEntity.ok(new TokenRefreshResponse(newAccessToken, requestToken));
|
||||||
|
})
|
||||||
|
.orElseGet(() -> {
|
||||||
|
log.error("Invalid refresh token: " + requestToken);
|
||||||
|
return ResponseEntity.status(403).body("Invalid refresh token");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.controller;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.dto.FileDownloadRequest;
|
||||||
|
import com.skycrate.backend.skycrateBackend.services.FileService;
|
||||||
|
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/files")
|
||||||
|
public class FileController {
|
||||||
|
|
||||||
|
private final FileService fileService;
|
||||||
|
private final JwtService jwtService;
|
||||||
|
|
||||||
|
public FileController(FileService fileService, JwtService jwtService) {
|
||||||
|
this.fileService = fileService;
|
||||||
|
this.jwtService = jwtService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/upload")
|
||||||
|
public ResponseEntity<?> uploadFile(
|
||||||
|
@RequestParam("file") MultipartFile file,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
String token = extractToken(request);
|
||||||
|
String username = jwtService.extractUsername(token);
|
||||||
|
|
||||||
|
fileService.uploadEncryptedFile(username, file.getBytes(), file.getOriginalFilename());
|
||||||
|
|
||||||
|
return ResponseEntity.ok("File uploaded and encrypted successfully.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
.body("Upload failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/download")
|
||||||
|
public ResponseEntity<?> downloadFile(
|
||||||
|
@RequestBody FileDownloadRequest fileDownloadRequest,
|
||||||
|
HttpServletRequest request
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
String token = extractToken(request);
|
||||||
|
String username = jwtService.extractUsername(token);
|
||||||
|
|
||||||
|
// Use the password and filename from the FileDownloadRequest DTO
|
||||||
|
byte[] decryptedData = fileService.downloadDecryptedFile(username, fileDownloadRequest.getPassword(), fileDownloadRequest.getFilename());
|
||||||
|
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileDownloadRequest.getFilename() + "\"")
|
||||||
|
.contentLength(decryptedData.length)
|
||||||
|
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
.body(decryptedData);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
.body("File download failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractToken(HttpServletRequest request) {
|
||||||
|
String authHeader = request.getHeader("Authorization");
|
||||||
|
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||||
|
throw new RuntimeException("Missing or invalid Authorization header");
|
||||||
|
}
|
||||||
|
return authHeader.substring(7);
|
||||||
|
}
|
||||||
|
}
|
||||||
+166
-170
@@ -2,9 +2,8 @@ package com.skycrate.backend.skycrateBackend.controller;
|
|||||||
|
|
||||||
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
|
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
|
||||||
import com.skycrate.backend.skycrateBackend.dto.ResponseDTO;
|
import com.skycrate.backend.skycrateBackend.dto.ResponseDTO;
|
||||||
import com.skycrate.backend.skycrateBackend.models.User;
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
import com.skycrate.backend.skycrateBackend.services.EncryptionUtil;
|
|
||||||
import com.skycrate.backend.skycrateBackend.services.HDFSOperations;
|
import com.skycrate.backend.skycrateBackend.services.HDFSOperations;
|
||||||
import com.skycrate.backend.skycrateBackend.utils.KeyUtil;
|
import com.skycrate.backend.skycrateBackend.utils.KeyUtil;
|
||||||
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
||||||
@@ -36,9 +35,6 @@ import javax.crypto.SecretKey;
|
|||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.io.File; // For java.io.File
|
import java.io.File; // For java.io.File
|
||||||
|
|
||||||
import static com.skycrate.backend.skycrateBackend.utils.KeyUtil.getPrivateKeyForUser;
|
|
||||||
import static com.skycrate.backend.skycrateBackend.utils.KeyUtil.getPublicKeyForUser;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/hdfs")
|
@RequestMapping("/api/hdfs")
|
||||||
public class HDFScontroller {
|
public class HDFScontroller {
|
||||||
@@ -66,71 +62,71 @@ public class HDFScontroller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/uploadFile")
|
// @PostMapping("/uploadFile")
|
||||||
public ResponseDTO uploadFile(
|
// public ResponseDTO uploadFile(
|
||||||
@RequestParam("file") MultipartFile file,
|
// @RequestParam("file") MultipartFile file,
|
||||||
@RequestParam String hdfsPath,
|
// @RequestParam String hdfsPath,
|
||||||
@RequestParam String uploadedFileName,
|
// @RequestParam String uploadedFileName,
|
||||||
@RequestParam String username) {
|
// @RequestParam String username) {
|
||||||
try {
|
// try {
|
||||||
// Retrieve the user from the database using the username
|
// // Retrieve the user from the database using the username
|
||||||
User user = userRepository.findByUsername(username).orElseThrow(() -> new RuntimeException("User not found"));
|
// User user = userRepository.findByUsername(username).orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
|
//
|
||||||
|
// // Get the public key from the user entity
|
||||||
|
// byte[] publicKeyBytes = user.getPublicKey();
|
||||||
|
// PublicKey publicKey = RSAKeyUtil.getPublicKeyFromBytes(publicKeyBytes);
|
||||||
|
//
|
||||||
|
// // Encrypt the file content using the public key
|
||||||
|
// byte[] encryptedData = encryptFile(file, publicKey);
|
||||||
|
//
|
||||||
|
// // Upload the encrypted file to HDFS
|
||||||
|
// hdfsOperations.uploadFile(encryptedData, hdfsPath, uploadedFileName, username);
|
||||||
|
//
|
||||||
|
// return new ResponseDTO("File uploaded successfully", true);
|
||||||
|
// } catch (IOException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// return new ResponseDTO("Failed to upload file locally: " + e.getMessage(), false);
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// return new ResponseDTO("Failed to upload file to HDFS: " + e.getMessage(), false);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Helper method to encrypt the file content using RSA encryption
|
||||||
|
// private byte[] encryptFile(MultipartFile file, PublicKey publicKey) throws Exception {
|
||||||
|
// // Step 1: Generate a random AES key
|
||||||
|
// SecretKey aesKey = generateAESKey();
|
||||||
|
//
|
||||||
|
// // Step 2: Encrypt the file data using AES
|
||||||
|
// Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||||
|
// aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
|
||||||
|
// byte[] fileData = file.getBytes();
|
||||||
|
// byte[] encryptedData = aesCipher.doFinal(fileData);
|
||||||
|
//
|
||||||
|
// // Step 3: Encrypt the AES key with RSA
|
||||||
|
// Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||||
|
// rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
|
// byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded());
|
||||||
|
//
|
||||||
|
// // Step 4: Combine the encrypted AES key and the encrypted data
|
||||||
|
// byte[] combined = new byte[4 + encryptedAesKey.length + encryptedData.length];
|
||||||
|
// combined[0] = (byte) (encryptedAesKey.length >> 24);
|
||||||
|
// combined[1] = (byte) (encryptedAesKey.length >> 16);
|
||||||
|
// combined[2] = (byte) (encryptedAesKey.length >> 8);
|
||||||
|
// combined[3] = (byte) encryptedAesKey.length;
|
||||||
|
//
|
||||||
|
// System.arraycopy(encryptedAesKey, 0, combined, 4, encryptedAesKey.length);
|
||||||
|
// System.arraycopy(encryptedData, 0, combined, 4 + encryptedAesKey.length, encryptedData.length);
|
||||||
|
//
|
||||||
|
// return combined;
|
||||||
|
// }
|
||||||
|
|
||||||
// Get the public key from the user entity
|
// // Generate a random AES key
|
||||||
byte[] publicKeyBytes = user.getPublicKey();
|
// private SecretKey generateAESKey() throws NoSuchAlgorithmException {
|
||||||
PublicKey publicKey = RSAKeyUtil.getPublicKeyFromBytes(publicKeyBytes);
|
// KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
||||||
|
// keyGen.init(256); // Use 256 bits for AES
|
||||||
// Encrypt the file content using the public key
|
// return keyGen.generateKey();
|
||||||
byte[] encryptedData = encryptFile(file, publicKey);
|
// }
|
||||||
|
|
||||||
// Upload the encrypted file to HDFS
|
|
||||||
hdfsOperations.uploadFile(encryptedData, hdfsPath, uploadedFileName, username);
|
|
||||||
|
|
||||||
return new ResponseDTO("File uploaded successfully", true);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return new ResponseDTO("Failed to upload file locally: " + e.getMessage(), false);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return new ResponseDTO("Failed to upload file to HDFS: " + e.getMessage(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to encrypt the file content using RSA encryption
|
|
||||||
private byte[] encryptFile(MultipartFile file, PublicKey publicKey) throws Exception {
|
|
||||||
// Step 1: Generate a random AES key
|
|
||||||
SecretKey aesKey = generateAESKey();
|
|
||||||
|
|
||||||
// Step 2: Encrypt the file data using AES
|
|
||||||
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
|
||||||
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
|
|
||||||
byte[] fileData = file.getBytes();
|
|
||||||
byte[] encryptedData = aesCipher.doFinal(fileData);
|
|
||||||
|
|
||||||
// Step 3: Encrypt the AES key with RSA
|
|
||||||
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
|
||||||
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
|
||||||
byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded());
|
|
||||||
|
|
||||||
// Step 4: Combine the encrypted AES key and the encrypted data
|
|
||||||
byte[] combined = new byte[4 + encryptedAesKey.length + encryptedData.length];
|
|
||||||
combined[0] = (byte) (encryptedAesKey.length >> 24);
|
|
||||||
combined[1] = (byte) (encryptedAesKey.length >> 16);
|
|
||||||
combined[2] = (byte) (encryptedAesKey.length >> 8);
|
|
||||||
combined[3] = (byte) encryptedAesKey.length;
|
|
||||||
|
|
||||||
System.arraycopy(encryptedAesKey, 0, combined, 4, encryptedAesKey.length);
|
|
||||||
System.arraycopy(encryptedData, 0, combined, 4 + encryptedAesKey.length, encryptedData.length);
|
|
||||||
|
|
||||||
return combined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a random AES key
|
|
||||||
private SecretKey generateAESKey() throws NoSuchAlgorithmException {
|
|
||||||
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
|
||||||
keyGen.init(256); // Use 256 bits for AES
|
|
||||||
return keyGen.generateKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String saveFileLocally(MultipartFile file) throws IOException {
|
private String saveFileLocally(MultipartFile file) throws IOException {
|
||||||
// Create a temporary directory if it doesn't exist
|
// Create a temporary directory if it doesn't exist
|
||||||
@@ -147,107 +143,107 @@ public class HDFScontroller {
|
|||||||
return path.toString(); // Return the local path for further processing
|
return path.toString(); // Return the local path for further processing
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/downloadFile")
|
// @PostMapping("/downloadFile")
|
||||||
public ResponseEntity<Resource> downloadFile(
|
// public ResponseEntity<Resource> downloadFile(
|
||||||
@RequestParam String hdfsEncPath,
|
// @RequestParam String hdfsEncPath,
|
||||||
@RequestParam String username) {
|
// @RequestParam String username) {
|
||||||
try {
|
// try {
|
||||||
// Extract the file name and extension
|
// // Extract the file name and extension
|
||||||
String encFileName = new File(hdfsEncPath).getName();
|
// String encFileName = new File(hdfsEncPath).getName();
|
||||||
String originalFileName = encFileName.replace(".enc", "");
|
// String originalFileName = encFileName.replace(".enc", "");
|
||||||
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
|
// String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
|
||||||
|
//
|
||||||
// Define local decrypted file path
|
// // Define local decrypted file path
|
||||||
String localDecryptedPath = "/SkyCrate/downloaded/" + originalFileName;
|
// String localDecryptedPath = "/SkyCrate/downloaded/" + originalFileName;
|
||||||
|
//
|
||||||
// Define HDFS paths for encrypted file
|
// // Define HDFS paths for encrypted file
|
||||||
String encFilePath = "/SkyCrate/downloaded/" + encFileName;
|
// String encFilePath = "/SkyCrate/downloaded/" + encFileName;
|
||||||
|
//
|
||||||
FileSystem fs = HDFSConfig.getHDFS();
|
// FileSystem fs = HDFSConfig.getHDFS();
|
||||||
|
//
|
||||||
// Download encrypted file from HDFS
|
// // Download encrypted file from HDFS
|
||||||
fs.copyToLocalFile(new org.apache.hadoop.fs.Path(hdfsEncPath), new org.apache.hadoop.fs.Path(encFilePath));
|
// fs.copyToLocalFile(new org.apache.hadoop.fs.Path(hdfsEncPath), new org.apache.hadoop.fs.Path(encFilePath));
|
||||||
|
//
|
||||||
// Retrieve the RSA private key for the user
|
// // Retrieve the RSA private key for the user
|
||||||
User user = userRepository.findByUsername(username)
|
// User user = userRepository.findByUsername(username)
|
||||||
.orElseThrow(() -> new RuntimeException("User not found"));
|
// .orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
PrivateKey privateKey = RSAKeyUtil.getPrivateKeyFromBytes(user.getPrivateKey());
|
// PrivateKey privateKey = RSAKeyUtil.getPrivateKeyFromBytes(user.getPrivateKey());
|
||||||
|
//
|
||||||
// Read the encrypted file content
|
// // Read the encrypted file content
|
||||||
byte[] encryptedFileContent = Files.readAllBytes(Paths.get(encFilePath));
|
// byte[] encryptedFileContent = Files.readAllBytes(Paths.get(encFilePath));
|
||||||
|
//
|
||||||
// Step 1: Extract the AES key length from the combined data
|
// // Step 1: Extract the AES key length from the combined data
|
||||||
int aesKeyLength = ((encryptedFileContent[0] & 0xFF) << 24) |
|
// int aesKeyLength = ((encryptedFileContent[0] & 0xFF) << 24) |
|
||||||
((encryptedFileContent[1] & 0xFF) << 16) |
|
// ((encryptedFileContent[1] & 0xFF) << 16) |
|
||||||
((encryptedFileContent[2] & 0xFF) << 8) |
|
// ((encryptedFileContent[2] & 0xFF) << 8) |
|
||||||
(encryptedFileContent[3] & 0xFF);
|
// (encryptedFileContent[3] & 0xFF);
|
||||||
|
//
|
||||||
// Step 2: Extract the encrypted AES key and encrypted data
|
// // Step 2: Extract the encrypted AES key and encrypted data
|
||||||
byte[] encryptedAesKey = new byte[aesKeyLength];
|
// byte[] encryptedAesKey = new byte[aesKeyLength];
|
||||||
byte[] encryptedData = new byte[encryptedFileContent.length - 4 - aesKeyLength];
|
// byte[] encryptedData = new byte[encryptedFileContent.length - 4 - aesKeyLength];
|
||||||
|
//
|
||||||
System.arraycopy(encryptedFileContent, 4, encryptedAesKey, 0, aesKeyLength);
|
// System.arraycopy(encryptedFileContent, 4, encryptedAesKey, 0, aesKeyLength);
|
||||||
System.arraycopy(encryptedFileContent, 4 + aesKeyLength, encryptedData, 0, encryptedData.length);
|
// System.arraycopy(encryptedFileContent, 4 + aesKeyLength, encryptedData, 0, encryptedData.length);
|
||||||
|
//
|
||||||
// Step 3: Decrypt the AES key using RSA
|
// // Step 3: Decrypt the AES key using RSA
|
||||||
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
// Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||||
rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
|
// rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
byte[] aesKeyBytes = rsaCipher.doFinal(encryptedAesKey);
|
// byte[] aesKeyBytes = rsaCipher.doFinal(encryptedAesKey);
|
||||||
|
//
|
||||||
// Create the AES key
|
// // Create the AES key
|
||||||
SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES");
|
// SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES");
|
||||||
|
//
|
||||||
// Step 4: Decrypt the data using AES
|
// // Step 4: Decrypt the data using AES
|
||||||
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
// Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||||
aesCipher.init(Cipher.DECRYPT_MODE, aesKey);
|
// aesCipher.init(Cipher.DECRYPT_MODE, aesKey);
|
||||||
|
//
|
||||||
// Decrypt the file content using the provided decrypt method
|
// // Decrypt the file content using the provided decrypt method
|
||||||
// byte[] decryptedFileContent = RSAKeyUtil.decrypt(encryptedFileContent, privateKey);
|
//// byte[] decryptedFileContent = RSAKeyUtil.decrypt(encryptedFileContent, privateKey);
|
||||||
byte[] decryptedFileContent = aesCipher.doFinal(encryptedData);
|
// byte[] decryptedFileContent = aesCipher.doFinal(encryptedData);
|
||||||
|
//
|
||||||
// Write the decrypted content to the original file
|
// // Write the decrypted content to the original file
|
||||||
Files.write(Paths.get(localDecryptedPath + "." + fileExtension), decryptedFileContent);
|
// Files.write(Paths.get(localDecryptedPath + "." + fileExtension), decryptedFileContent);
|
||||||
|
//
|
||||||
|
//
|
||||||
// Log the file creation
|
// // Log the file creation
|
||||||
if (Files.exists(Paths.get(localDecryptedPath + "." + fileExtension))) {
|
// if (Files.exists(Paths.get(localDecryptedPath + "." + fileExtension))) {
|
||||||
System.out.println("File created successfully at: " + localDecryptedPath + "." + fileExtension);
|
// System.out.println("File created successfully at: " + localDecryptedPath + "." + fileExtension);
|
||||||
} else {
|
// } else {
|
||||||
System.out.println("Failed to create file at: " + localDecryptedPath + "." + fileExtension);
|
// System.out.println("Failed to create file at: " + localDecryptedPath + "." + fileExtension);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Create the decrypted file resource
|
// // Create the decrypted file resource
|
||||||
File decryptedFile = new File(localDecryptedPath + "." + fileExtension);
|
// File decryptedFile = new File(localDecryptedPath + "." + fileExtension);
|
||||||
Resource resource = new FileSystemResource(decryptedFile);
|
// Resource resource = new FileSystemResource(decryptedFile);
|
||||||
|
//
|
||||||
// Return the file as a response
|
// // Return the file as a response
|
||||||
return ResponseEntity.ok()
|
// return ResponseEntity.ok()
|
||||||
.contentLength(decryptedFile.length())
|
// .contentLength(decryptedFile.length())
|
||||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
// .contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + decryptedFile.getName() + "\"")
|
// .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + decryptedFile.getName() + "\"")
|
||||||
.body(resource);
|
// .body(resource);
|
||||||
|
//
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
e.printStackTrace();
|
// e.printStackTrace();
|
||||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
.body(null);
|
// .body(null);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
public void initializeKeysForUser(String username) {
|
// public void initializeKeysForUser(String username) {
|
||||||
try {
|
// try {
|
||||||
// Check if the public key file exists
|
// // Check if the public key file exists
|
||||||
Path publicKeyPath = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_public.key");
|
// Path publicKeyPath = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_public.key");
|
||||||
if (!Files.exists(publicKeyPath)) {
|
// if (!Files.exists(publicKeyPath)) {
|
||||||
// Generate and store keys if they do not exist
|
// // Generate and store keys if they do not exist
|
||||||
KeyUtil.generateAndStoreKeyPair(username);
|
// KeyUtil.generateAndStoreKeyPair(username);
|
||||||
}
|
// }
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
e.printStackTrace();
|
// e.printStackTrace();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
@DeleteMapping("/deleteFile")
|
@DeleteMapping("/deleteFile")
|
||||||
public ResponseDTO deleteFile(@RequestParam String hdfsPath) {
|
public ResponseDTO deleteFile(@RequestParam String hdfsPath) {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.dto;
|
||||||
|
|
||||||
|
public class FileDownloadRequest {
|
||||||
|
private String filename;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilename(String filename) {
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.dto;
|
||||||
|
|
||||||
|
public class LoginRequest {
|
||||||
|
private String email;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
// Getters and setters
|
||||||
|
public String getEmail() { return email; }
|
||||||
|
public void setEmail(String email) { this.email = email; }
|
||||||
|
|
||||||
|
public String getPassword() { return password; }
|
||||||
|
public void setPassword(String password) { this.password = password; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.dto;
|
||||||
|
|
||||||
|
public class LoginResponse {
|
||||||
|
private String accessToken;
|
||||||
|
private String refreshToken;
|
||||||
|
private String tokenType = "Bearer";
|
||||||
|
|
||||||
|
public LoginResponse(String accessToken, String refreshToken) {
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
public String getAccessToken() { return accessToken; }
|
||||||
|
public String getRefreshToken() { return refreshToken; }
|
||||||
|
public String getTokenType() { return tokenType; }
|
||||||
|
}
|
||||||
@@ -1,46 +1,46 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.dto;
|
package com.skycrate.backend.skycrateBackend.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.Email;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
public class RegisterUserDto {
|
public class RegisterUserDto {
|
||||||
|
|
||||||
|
@NotBlank(message = "Email is required")
|
||||||
|
@Email(message = "Email should be valid")
|
||||||
private String email;
|
private String email;
|
||||||
|
|
||||||
|
@NotBlank(message = "Password is required")
|
||||||
|
@Size(min = 8, message = "Password must be at least 8 characters")
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
@NotBlank(message = "Username is required")
|
||||||
|
@Pattern(regexp = "^[a-zA-Z0-9]+$", message = "Username must be alphanumeric")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@NotBlank(message = "Full name is required")
|
||||||
|
private String fullname;
|
||||||
|
|
||||||
|
@NotBlank(message = "First name is required")
|
||||||
private String firstname;
|
private String firstname;
|
||||||
|
|
||||||
|
@NotBlank(message = "Last name is required")
|
||||||
private String lastname;
|
private String lastname;
|
||||||
|
|
||||||
public String getEmail() {
|
// Getters
|
||||||
return email;
|
public String getEmail() { return email; }
|
||||||
}
|
public String getPassword() { return password; }
|
||||||
|
public String getUsername() { return username; }
|
||||||
|
public String getFullname() { return fullname; }
|
||||||
|
public String getFirstname() { return firstname; }
|
||||||
|
public String getLastname() { return lastname; }
|
||||||
|
|
||||||
public RegisterUserDto setEmail(String email) {
|
// Setters
|
||||||
this.email = email;
|
public void setEmail(String email) { this.email = email; }
|
||||||
return this;
|
public void setPassword(String password) { this.password = password; }
|
||||||
}
|
public void setUsername(String username) { this.username = username; }
|
||||||
|
public void setFullname(String fullname) { this.fullname = fullname; }
|
||||||
public String getPassword() {
|
public void setFirstname(String firstname) { this.firstname = firstname; }
|
||||||
return password;
|
public void setLastname(String lastname) { this.lastname = lastname; }
|
||||||
}
|
|
||||||
|
|
||||||
public RegisterUserDto setPassword(String password) {
|
|
||||||
this.password = password;
|
|
||||||
return this;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFirstname() {
|
|
||||||
return firstname;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegisterUserDto setFirstname(String firstname) {
|
|
||||||
this.firstname = firstname;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLastname() {
|
|
||||||
return lastname;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegisterUserDto setLastname(String lastname) {
|
|
||||||
this.lastname = lastname;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.dto;
|
||||||
|
|
||||||
|
public class SignupRequest {
|
||||||
|
private String username;
|
||||||
|
private String email;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setters
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.dto;
|
||||||
|
|
||||||
|
public class TokenRefreshRequest {
|
||||||
|
private String refreshToken;
|
||||||
|
|
||||||
|
public String getRefreshToken() {
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRefreshToken(String refreshToken) {
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.dto;
|
||||||
|
|
||||||
|
public class TokenRefreshResponse {
|
||||||
|
private String accessToken;
|
||||||
|
private String refreshToken;
|
||||||
|
private String tokenType = "Bearer";
|
||||||
|
|
||||||
|
public TokenRefreshResponse(String accessToken, String refreshToken) {
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
public String getAccessToken() { return accessToken; }
|
||||||
|
public String getRefreshToken() { return refreshToken; }
|
||||||
|
public String getTokenType() { return tokenType; }
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.dto;
|
|
||||||
|
|
||||||
import com.skycrate.backend.skycrateBackend.services.EncryptionUtil;
|
|
||||||
|
|
||||||
import java.security.KeyPair;
|
|
||||||
|
|
||||||
public class User {
|
|
||||||
private String username;
|
|
||||||
private KeyPair keyPair;
|
|
||||||
|
|
||||||
public User(String username) throws Exception {
|
|
||||||
this.username = username;
|
|
||||||
this.keyPair = EncryptionUtil.generateKeyPair();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyPair getKeyPair() {
|
|
||||||
return keyPair;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "file_metadata")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class FileMetadata {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String filePath;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
@Column(nullable = false)
|
||||||
|
private byte[] salt;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
@Column(nullable = false)
|
||||||
|
private byte[] iv;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
@Column(nullable = false, name = "encrypted_key", columnDefinition = "LONGBLOB")
|
||||||
|
private byte[] encryptedKey;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private long uploadedAt;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class RefreshToken {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "user_id", referencedColumnName = "id")
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
private Instant expiryDate;
|
||||||
|
|
||||||
|
// Getters and setters
|
||||||
|
|
||||||
|
public Long getId() { return id; }
|
||||||
|
|
||||||
|
public String getToken() { return token; }
|
||||||
|
public void setToken(String token) { this.token = token; }
|
||||||
|
|
||||||
|
public User getUser() { return user; }
|
||||||
|
public void setUser(User user) { this.user = user; }
|
||||||
|
|
||||||
|
public Instant getExpiryDate() { return expiryDate; }
|
||||||
|
public void setExpiryDate(Instant expiryDate) { this.expiryDate = expiryDate; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "users")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class User implements UserDetails {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String fullname;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
private byte[] publicKey;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
private byte[] privateKey;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
@Column(nullable = false)
|
||||||
|
private byte[] privateKeySalt;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
@Column(nullable = false)
|
||||||
|
private byte[] privateKeyIv;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
public User(String email, String password, String username, String fullname,
|
||||||
|
byte[] publicKey, byte[] privateKey,
|
||||||
|
byte[] privateKeySalt, byte[] privateKeyIv) {
|
||||||
|
this.email = email;
|
||||||
|
this.password = password;
|
||||||
|
this.username = username;
|
||||||
|
this.fullname = fullname;
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
this.privateKeySalt = privateKeySalt;
|
||||||
|
this.privateKeyIv = privateKeyIv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- UserDetails interface methods ---
|
||||||
|
@Override
|
||||||
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
|
return List.of(); // No roles assigned currently
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPassword() {
|
||||||
|
return this.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonExpired() { return true; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonLocked() { return true; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCredentialsNonExpired() { return true; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() { return true; }
|
||||||
|
}
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.models;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
|
|
||||||
@Table(name = "users")
|
|
||||||
@Entity
|
|
||||||
public class User implements UserDetails {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
||||||
@Column(nullable = false)
|
|
||||||
private Integer id;
|
|
||||||
|
|
||||||
@Column(nullable = false)
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
@Column(unique = true, nullable = false)
|
|
||||||
private String email;
|
|
||||||
|
|
||||||
@Column(nullable = false)
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
// ✅ Add RSA key fields
|
|
||||||
@Lob
|
|
||||||
@Column(name = "public_key", columnDefinition = "BLOB")
|
|
||||||
private byte[] publicKey;
|
|
||||||
|
|
||||||
@Lob
|
|
||||||
@Column(name = "private_key", columnDefinition = "BLOB")
|
|
||||||
private byte[] privateKey;
|
|
||||||
|
|
||||||
|
|
||||||
@CreationTimestamp
|
|
||||||
@Column(updatable = false, name = "created_at")
|
|
||||||
private Date createdAt;
|
|
||||||
|
|
||||||
public User() {}
|
|
||||||
|
|
||||||
public User(String firstname, String lastname, String email, String password) {
|
|
||||||
this.username = firstname + lastname;
|
|
||||||
this.email = email;
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ⬇️ Required by Spring Security
|
|
||||||
@Override
|
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsername() {
|
|
||||||
return email;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAccountNonExpired() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAccountNonLocked() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCredentialsNonExpired() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ⬇️ Getters and Setters
|
|
||||||
public Integer getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Integer id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFullname(String firstname, String lastname) {
|
|
||||||
this.username = firstname + lastname;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFullname() {
|
|
||||||
return this.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEmail(String email) {
|
|
||||||
this.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPassword(String password) {
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreatedAt(Date createdAt) {
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Getters and setters for RSA keys
|
|
||||||
public byte[] getPublicKey() {
|
|
||||||
return publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPublicKey(byte[] publicKey) {
|
|
||||||
this.publicKey = publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getPrivateKey() {
|
|
||||||
return privateKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPrivateKey(byte[] privateKey) {
|
|
||||||
this.privateKey = privateKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.repository;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.FileMetadata;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface FileMetadataRepository extends JpaRepository<FileMetadata, Long> {
|
||||||
|
Optional<FileMetadata> findByUsernameAndFilePath(String username, String filePath);
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.repository;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.RefreshToken;
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> {
|
||||||
|
Optional<RefreshToken> findByToken(String token);
|
||||||
|
@Transactional
|
||||||
|
@Modifying
|
||||||
|
@Query("DELETE FROM RefreshToken t WHERE t.user = :user")
|
||||||
|
void deleteByUser(User user);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.repository;
|
|
||||||
|
|
||||||
import com.skycrate.backend.skycrateBackend.dto.User;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class UserManager {
|
|
||||||
private Map<String, User> users = new HashMap<>();
|
|
||||||
|
|
||||||
public User getUser(String username) throws Exception {
|
|
||||||
if (!users.containsKey(username)) {
|
|
||||||
users.put(username, new User(username));
|
|
||||||
}
|
|
||||||
return users.get(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean authenticate(String username, String password) {
|
|
||||||
// Implement your authentication logic here
|
|
||||||
return "admin".equals(username) && "password123".equals(password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@ package com.skycrate.backend.skycrateBackend.repository;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
import org.springframework.data.repository.CrudRepository;
|
||||||
import com.skycrate.backend.skycrateBackend.models.User;
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
public interface UserRepository extends CrudRepository<User,Integer> {
|
public interface UserRepository extends CrudRepository<User,Integer> {
|
||||||
Optional<User> findByEmail(String email);
|
Optional<User> findByEmail(String email);
|
||||||
// Custom query method to find user by username
|
// Custom query method to find user by username
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.security;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
import javax.crypto.spec.*;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class EncryptionService {
|
||||||
|
|
||||||
|
private static final int KEY_LENGTH = 256;
|
||||||
|
private static final int ITERATIONS = 65536;
|
||||||
|
private static final int SALT_LENGTH = 16;
|
||||||
|
private static final int IV_LENGTH = 12;
|
||||||
|
|
||||||
|
public static byte[] generateSalt() {
|
||||||
|
byte[] salt = new byte[SALT_LENGTH];
|
||||||
|
new SecureRandom().nextBytes(salt);
|
||||||
|
return salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SecretKey deriveKey(String password, byte[] salt) throws Exception {
|
||||||
|
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_LENGTH);
|
||||||
|
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
||||||
|
return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] encrypt(byte[] plaintext, SecretKey key, byte[] iv) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||||
|
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
|
||||||
|
return cipher.doFinal(plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] decrypt(byte[] ciphertext, SecretKey key, byte[] iv) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||||
|
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, key, spec);
|
||||||
|
return cipher.doFinal(ciphertext);
|
||||||
|
}
|
||||||
|
}
|
||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.security;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
|
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private final JwtService jwtService;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
private final TokenBlacklistService tokenBlacklistService;
|
||||||
|
|
||||||
|
public JwtAuthenticationFilter(JwtService jwtService,
|
||||||
|
UserRepository userRepository,
|
||||||
|
TokenBlacklistService tokenBlacklistService) {
|
||||||
|
this.jwtService = jwtService;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.tokenBlacklistService = tokenBlacklistService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
FilterChain filterChain)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
String path = request.getRequestURI();
|
||||||
|
if (path.startsWith("/api/auth") || path.startsWith("/actuator")) {
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String authHeader = request.getHeader("Authorization");
|
||||||
|
final String jwt;
|
||||||
|
final String username;
|
||||||
|
|
||||||
|
if (!StringUtils.hasText(authHeader) || !authHeader.startsWith("Bearer ")) {
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jwt = authHeader.substring(7);
|
||||||
|
|
||||||
|
// Check if token is blacklisted
|
||||||
|
if (tokenBlacklistService.isTokenBlacklisted(jwt)) {
|
||||||
|
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
response.getWriter().write("Token has been blacklisted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
username = jwtService.extractUsername(jwt); // This is actually the `username`, not email
|
||||||
|
} catch (Exception e) {
|
||||||
|
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
response.getWriter().write("Invalid JWT token");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||||
|
// ❗ Use username to find the user
|
||||||
|
User user = userRepository.findByUsername(username).orElse(null);
|
||||||
|
|
||||||
|
if (user != null && jwtService.isTokenValid(jwt, user)) {
|
||||||
|
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
|
||||||
|
user, null, user.getAuthorities());
|
||||||
|
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authToken);
|
||||||
|
} else {
|
||||||
|
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
response.getWriter().write("Expired or invalid JWT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.security;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TokenBlacklistService {
|
||||||
|
|
||||||
|
private final Cache<String, Boolean> blacklistCache;
|
||||||
|
|
||||||
|
public TokenBlacklistService() {
|
||||||
|
this.blacklistCache = Caffeine.newBuilder()
|
||||||
|
.expireAfterWrite(1, TimeUnit.HOURS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void blacklistToken(String token) {
|
||||||
|
blacklistCache.put(token, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTokenBlacklisted(String token) {
|
||||||
|
return blacklistCache.getIfPresent(token) != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+82
-18
@@ -1,18 +1,26 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.services;
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
|
||||||
|
import com.skycrate.backend.skycrateBackend.dto.LoginUserDto;
|
||||||
|
import com.skycrate.backend.skycrateBackend.dto.RegisterUserDto;
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
|
import com.skycrate.backend.skycrateBackend.utils.EncryptionUtil;
|
||||||
|
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.skycrate.backend.skycrateBackend.dto.LoginUserDto;
|
import javax.crypto.SecretKey;
|
||||||
import com.skycrate.backend.skycrateBackend.dto.RegisterUserDto;
|
|
||||||
import com.skycrate.backend.skycrateBackend.models.User;
|
|
||||||
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
|
||||||
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
|
||||||
|
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class AuthenticationService {
|
public class AuthenticationService {
|
||||||
@@ -20,30 +28,67 @@ public class AuthenticationService {
|
|||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
private final AuthenticationManager authenticationManager;
|
private final AuthenticationManager authenticationManager;
|
||||||
|
private final KeyCacheService keyCacheService;
|
||||||
|
|
||||||
public AuthenticationService(UserRepository userRepository, AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder) {
|
private static final Logger log = LoggerFactory.getLogger(AuthenticationService.class);
|
||||||
|
|
||||||
|
public AuthenticationService(UserRepository userRepository,
|
||||||
|
AuthenticationManager authenticationManager,
|
||||||
|
PasswordEncoder passwordEncoder,
|
||||||
|
KeyCacheService keyCacheService) {
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
this.passwordEncoder = passwordEncoder;
|
this.passwordEncoder = passwordEncoder;
|
||||||
this.authenticationManager = authenticationManager;
|
this.authenticationManager = authenticationManager;
|
||||||
|
this.keyCacheService = keyCacheService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public User signUp(RegisterUserDto inputUser) {
|
public User signUp(RegisterUserDto inputUser) {
|
||||||
User user = new User(
|
// Generate RSA key pair
|
||||||
inputUser.getFirstname(),
|
KeyPair keyPair;
|
||||||
inputUser.getLastname(),
|
|
||||||
inputUser.getEmail(),
|
|
||||||
passwordEncoder.encode(inputUser.getPassword())
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
KeyPair keyPair = RSAKeyUtil.generateKeyPair();
|
keyPair = RSAKeyUtil.generateKeyPair();
|
||||||
user.setPublicKey(keyPair.getPublic().getEncoded());
|
|
||||||
user.setPrivateKey(keyPair.getPrivate().getEncoded());
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
throw new RuntimeException("Failed to generate RSA key pair", e);
|
throw new RuntimeException("Failed to generate RSA key pair", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return userRepository.save(user);
|
// Encrypt private key using password-derived AES key
|
||||||
|
byte[] salt = EncryptionUtil.generateSalt();
|
||||||
|
byte[] iv = EncryptionUtil.generateIv();
|
||||||
|
byte[] encryptedPrivateKey;
|
||||||
|
try {
|
||||||
|
SecretKey aesKey = EncryptionUtil.deriveKey(inputUser.getPassword().toCharArray(), salt);
|
||||||
|
encryptedPrivateKey = EncryptionUtil.encrypt(keyPair.getPrivate().getEncoded(), aesKey, iv);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to encrypt private key", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create user entity with encrypted private key, salt, and iv
|
||||||
|
User user = User.builder()
|
||||||
|
.fullname(inputUser.getFirstname() + " " + inputUser.getLastname())
|
||||||
|
.username(inputUser.getUsername())
|
||||||
|
.email(inputUser.getEmail())
|
||||||
|
.password(passwordEncoder.encode(inputUser.getPassword()))
|
||||||
|
.publicKey(keyPair.getPublic().getEncoded())
|
||||||
|
.privateKey(encryptedPrivateKey)
|
||||||
|
.privateKeySalt(salt)
|
||||||
|
.privateKeyIv(iv)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Save user
|
||||||
|
User savedUser = userRepository.save(user);
|
||||||
|
|
||||||
|
// Create HDFS directory in root with username
|
||||||
|
try {
|
||||||
|
FileSystem fs = HDFSConfig.getHDFS();
|
||||||
|
Path userDir = new Path("/" + savedUser.getUsername());
|
||||||
|
if (!fs.exists(userDir)) {
|
||||||
|
fs.mkdirs(userDir);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to create HDFS directory for user: " + savedUser.getUsername(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return savedUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public User authenticate(LoginUserDto inputUser) {
|
public User authenticate(LoginUserDto inputUser) {
|
||||||
@@ -54,4 +99,23 @@ public class AuthenticationService {
|
|||||||
return userRepository.findByEmail(inputUser.getEmail())
|
return userRepository.findByEmail(inputUser.getEmail())
|
||||||
.orElseThrow(() -> new RuntimeException("User not found"));
|
.orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(value = "decryptedPrivateKeys", key = "#userId")
|
||||||
|
public byte[] getDecryptedPrivateKey(String userId, String password) throws Exception {
|
||||||
|
User user = userRepository.findById(Integer.valueOf(userId))
|
||||||
|
.orElseThrow(() -> new RuntimeException("User not found: " + userId));
|
||||||
|
|
||||||
|
log.info("Caching decrypted private key for userId: {}", userId);
|
||||||
|
|
||||||
|
SecretKey derivedKey = EncryptionUtil.deriveKey(password.toCharArray(), user.getPrivateKeySalt());
|
||||||
|
byte[] decryptedPrivateKeyBytes = EncryptionUtil.decrypt(user.getPrivateKey(), derivedKey, user.getPrivateKeyIv());
|
||||||
|
return decryptedPrivateKeyBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEvict(value = "decryptedPrivateKeys", key = "#userId")
|
||||||
|
public void clearDecryptedPrivateKeyCache(String userId) {
|
||||||
|
// This method will clear the cached decrypted private key for the given userId
|
||||||
|
log.info("Clearing Caching decrypted private key for userId: {}", userId);
|
||||||
|
keyCacheService.clearKey(Long.valueOf(userId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,102 +1,79 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.services;
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
|
||||||
|
|
||||||
import javax.crypto.*;
|
import javax.crypto.*;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.security.spec.KeySpec;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
public class EncryptionUtil {
|
public class EncryptionUtil {
|
||||||
private static final String RSA_ALGORITHM = "RSA";
|
|
||||||
private static final String AES_ALGORITHM = "AES";
|
|
||||||
private static final int RSA_KEY_SIZE = 2048;
|
|
||||||
private static final int AES_KEY_SIZE = 256;
|
|
||||||
|
|
||||||
// Generate RSA Key Pair (Public & Private)
|
private static final int SALT_LENGTH = 16; // in bytes
|
||||||
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
|
private static final int IV_LENGTH = 16; // for AES CBC
|
||||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(RSA_ALGORITHM);
|
private static final int ITERATIONS = 65536;
|
||||||
keyGen.initialize(RSA_KEY_SIZE);
|
private static final int KEY_LENGTH = 256; // bits
|
||||||
return keyGen.generateKeyPair();
|
|
||||||
|
// --- AES key derivation using PBKDF2 ---
|
||||||
|
public static SecretKey deriveAESKey(char[] password, byte[] salt)
|
||||||
|
throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||||
|
|
||||||
|
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
||||||
|
|
||||||
|
KeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
|
||||||
|
byte[] keyBytes = factory.generateSecret(spec).getEncoded();
|
||||||
|
|
||||||
|
return new SecretKeySpec(keyBytes, "AES");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt data using AES (AES Key is encrypted using RSA)
|
// --- Encrypt data using AES-CBC ---
|
||||||
// public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
|
public static byte[] encrypt(byte[] data, SecretKey key, byte[] iv)
|
||||||
// // Step 1: Generate AES Key
|
throws GeneralSecurityException {
|
||||||
// SecretKey aesKey = generateAESKey();
|
|
||||||
//
|
|
||||||
// // Encrypt data using AES
|
|
||||||
// Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
|
||||||
// aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
|
|
||||||
// byte[] encryptedData = aesCipher.doFinal(data);
|
|
||||||
//
|
|
||||||
// // Encrypt the AES key with RSA
|
|
||||||
// Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
|
||||||
// rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
|
||||||
// byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded());
|
|
||||||
//
|
|
||||||
// // Step 4: Combine encrypted AES key and encrypted data into one array
|
|
||||||
// byte[] combined = new byte[4 + encryptedAesKey.length + encryptedData.length];
|
|
||||||
//
|
|
||||||
// // First 4 bytes indicate the length of the AES encrypted key
|
|
||||||
// combined[0] = (byte) (encryptedAesKey.length >> 24);
|
|
||||||
// combined[1] = (byte) (encryptedAesKey.length >> 16);
|
|
||||||
// combined[2] = (byte) (encryptedAesKey.length >> 8);
|
|
||||||
// combined[3] = (byte) encryptedAesKey.length;
|
|
||||||
//
|
|
||||||
// // Copy AES Key and Encrypted Data into the combined array
|
|
||||||
// System.arraycopy(encryptedAesKey, 0, combined, 4, encryptedAesKey.length);
|
|
||||||
// System.arraycopy(encryptedData, 0, combined, 4 + encryptedAesKey.length, encryptedData.length);
|
|
||||||
//
|
|
||||||
// return combined;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||||
SecretKey aesKey = RSAKeyUtil.generateAESKey(256); // Ensure 256 bits
|
|
||||||
byte[] encryptedData = encryptDataWithAES(data, aesKey);
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
byte[] encryptedAesKey = RSAKeyUtil.encryptAESKey(aesKey, publicKey);
|
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
|
||||||
return combineEncryptedData(encryptedAesKey, encryptedData);
|
|
||||||
|
return cipher.doFinal(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] encryptDataWithAES(byte[] data, SecretKey aesKey) throws Exception {
|
// --- Decrypt data using AES-CBC ---
|
||||||
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
public static byte[] decrypt(byte[] encryptedData, SecretKey key, byte[] iv)
|
||||||
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
|
throws GeneralSecurityException {
|
||||||
return aesCipher.doFinal(data);
|
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||||
|
|
||||||
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
|
||||||
|
|
||||||
|
return cipher.doFinal(encryptedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] combineEncryptedData(byte[] encryptedAesKey, byte[] encryptedData) {
|
// --- Generate random salt ---
|
||||||
byte[] combined = new byte[4 + encryptedAesKey.length + encryptedData.length];
|
public static byte[] generateSalt() {
|
||||||
System.arraycopy(encryptedAesKey, 0, combined, 4, encryptedAesKey.length);
|
byte[] salt = new byte[SALT_LENGTH];
|
||||||
System.arraycopy(encryptedData, 0, combined, 4 + encryptedAesKey.length, encryptedData.length);
|
new SecureRandom().nextBytes(salt);
|
||||||
return combined;
|
return salt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Generate random IV ---
|
||||||
|
public static byte[] generateIV() {
|
||||||
|
byte[] iv = new byte[IV_LENGTH];
|
||||||
|
new SecureRandom().nextBytes(iv);
|
||||||
|
return iv;
|
||||||
|
}
|
||||||
|
|
||||||
// Decrypt data using RSA (AES Key is decrypted using RSA, then used for AES decryption)
|
// --- Optional: Utility to base64 encode data ---
|
||||||
public static byte[] decrypt(byte[] encryptedCombined, PrivateKey privateKey) throws Exception {
|
public static String encodeBase64(byte[] data) {
|
||||||
// Step 1: Extract AES Key length from the combined data
|
return Base64.getEncoder().encodeToString(data);
|
||||||
int aesKeyLength = ((encryptedCombined[0] & 0xFF) << 24) |
|
}
|
||||||
((encryptedCombined[1] & 0xFF) << 16) |
|
|
||||||
((encryptedCombined[2] & 0xFF) << 8) |
|
|
||||||
(encryptedCombined[3] & 0xFF);
|
|
||||||
|
|
||||||
// Step 2: Extract the encrypted AES key and encrypted data
|
public static byte[] decodeBase64(String base64) {
|
||||||
byte[] encryptedAesKey = new byte[aesKeyLength];
|
return Base64.getDecoder().decode(base64);
|
||||||
byte[] encryptedData = new byte[encryptedCombined.length - 4 - aesKeyLength];
|
|
||||||
|
|
||||||
System.arraycopy(encryptedCombined, 4, encryptedAesKey, 0, aesKeyLength);
|
|
||||||
System.arraycopy(encryptedCombined, 4 + aesKeyLength, encryptedData, 0, encryptedData.length);
|
|
||||||
|
|
||||||
// Step 3: Decrypt the AES key using RSA
|
|
||||||
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
|
||||||
rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
|
|
||||||
byte[] aesKeyBytes = rsaCipher.doFinal(encryptedAesKey);
|
|
||||||
|
|
||||||
// Create AES key
|
|
||||||
SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES");
|
|
||||||
|
|
||||||
// Decrypt the data using AES
|
|
||||||
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
|
||||||
aesCipher.init(Cipher.DECRYPT_MODE, aesKey);
|
|
||||||
return aesCipher.doFinal(encryptedData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.FileMetadata;
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
|
import com.skycrate.backend.skycrateBackend.repository.FileMetadataRepository;
|
||||||
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
|
import com.skycrate.backend.skycrateBackend.utils.EncryptionUtil;
|
||||||
|
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
||||||
|
import org.apache.hadoop.fs.FSDataInputStream;
|
||||||
|
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FileService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FileService.class);
|
||||||
|
private final AuthenticationService authenticationService;
|
||||||
|
private final FileMetadataRepository fileMetadataRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public FileService(FileMetadataRepository fileMetadataRepository, UserRepository userRepository, AuthenticationService authenticationService) {
|
||||||
|
this.fileMetadataRepository = fileMetadataRepository;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.authenticationService = authenticationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void uploadEncryptedFile(String username, byte[] fileContent, String filename) throws Exception {
|
||||||
|
log.info("Starting upload for user={}, file={}", username, filename);
|
||||||
|
try {
|
||||||
|
User user = userRepository.findByUsername(username)
|
||||||
|
.orElseThrow(() -> new RuntimeException("User not found: " + username));
|
||||||
|
|
||||||
|
SecretKey aesKey = EncryptionUtil.generateAESKey();
|
||||||
|
byte[] salt = EncryptionUtil.generateSalt(); // reserved for future use
|
||||||
|
byte[] iv = EncryptionUtil.generateIv();
|
||||||
|
|
||||||
|
byte[] encryptedData = EncryptionUtil.encrypt(fileContent, aesKey, iv);
|
||||||
|
|
||||||
|
PublicKey publicKey = RSAKeyUtil.decodePublicKey(user.getPublicKey());
|
||||||
|
byte[] encryptedAesKey = EncryptionUtil.encryptRSA(aesKey.getEncoded(), publicKey);
|
||||||
|
|
||||||
|
Path userDir = new Path("/" + username);
|
||||||
|
Path filePath = new Path(userDir, filename);
|
||||||
|
FileSystem fs = HDFSConfig.getHDFS();
|
||||||
|
|
||||||
|
if (!fs.exists(userDir)) {
|
||||||
|
log.info("Creating directory in HDFS: {}", userDir);
|
||||||
|
fs.mkdirs(userDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Writing encrypted file to HDFS: {}", filePath);
|
||||||
|
try (FSDataOutputStream out = fs.create(filePath, true);
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(encryptedData)) {
|
||||||
|
in.transferTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileMetadata metadata = FileMetadata.builder()
|
||||||
|
.username(username)
|
||||||
|
.filePath(filePath.toString())
|
||||||
|
.salt(salt)
|
||||||
|
.iv(iv)
|
||||||
|
.encryptedKey(encryptedAesKey)
|
||||||
|
.uploadedAt(System.currentTimeMillis())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
fileMetadataRepository.save(metadata);
|
||||||
|
log.info("Upload complete: file={} for user={}", filename, username);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error during file upload for user={}, file={}: {}", username, filename, e.getMessage(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] downloadDecryptedFile(String username, String password, String filename) throws Exception {
|
||||||
|
log.info("Download request: user={}, file={}", username, filename);
|
||||||
|
try {
|
||||||
|
User user = userRepository.findByUsername(username)
|
||||||
|
.orElseThrow(() -> new RuntimeException("User not found: " + username));
|
||||||
|
|
||||||
|
Path filePath = new Path("/" + username + "/" + filename);
|
||||||
|
FileMetadata metadata = fileMetadataRepository.findByUsernameAndFilePath(username, filePath.toString())
|
||||||
|
.orElseThrow(() -> new RuntimeException("File metadata not found for: " + filePath));
|
||||||
|
|
||||||
|
// Use the cached decrypted private key
|
||||||
|
byte[] decryptedPrivateKeyBytes = authenticationService.getDecryptedPrivateKey(String.valueOf(user.getId()), password);
|
||||||
|
PrivateKey privateKey = RSAKeyUtil.decodePrivateKey(decryptedPrivateKeyBytes);
|
||||||
|
|
||||||
|
byte[] aesKeyBytes = EncryptionUtil.decryptRSA(metadata.getEncryptedKey(), privateKey);
|
||||||
|
SecretKey aesKey = EncryptionUtil.rebuildAESKey(aesKeyBytes);
|
||||||
|
|
||||||
|
FileSystem fs = HDFSConfig.getHDFS();
|
||||||
|
byte[] encryptedData;
|
||||||
|
try (FSDataInputStream in = fs.open(filePath)) {
|
||||||
|
encryptedData = in.readAllBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
return EncryptionUtil.decrypt(encryptedData, aesKey, metadata.getIv());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Download failed for user={}, file={}: {}", username, filename, e.getMessage(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.services;
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
|
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
|
||||||
import com.skycrate.backend.skycrateBackend.models.User;
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
||||||
import org.apache.hadoop.fs.FSDataOutputStream;
|
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||||
@@ -120,41 +120,41 @@ public class HDFSOperations {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public void uploadFile(byte[] fileData, String hdfsPath, String uploadedFileName, String username) {
|
// public void uploadFile(byte[] fileData, String hdfsPath, String uploadedFileName, String username) {
|
||||||
try {
|
// try {
|
||||||
FileSystem fs = HDFSConfig.getHDFS();
|
// FileSystem fs = HDFSConfig.getHDFS();
|
||||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData);
|
// ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData);
|
||||||
String finalHdfsPath = hdfsPath.endsWith("/") ? hdfsPath + uploadedFileName : hdfsPath + "/" + uploadedFileName;
|
// String finalHdfsPath = hdfsPath.endsWith("/") ? hdfsPath + uploadedFileName : hdfsPath + "/" + uploadedFileName;
|
||||||
Path hdfsFilePath = new Path(finalHdfsPath);
|
// Path hdfsFilePath = new Path(finalHdfsPath);
|
||||||
try (FSDataOutputStream outputStream = fs.create(hdfsFilePath)) {
|
// try (FSDataOutputStream outputStream = fs.create(hdfsFilePath)) {
|
||||||
IOUtils.copyBytes(inputStream, outputStream, 4096, true);
|
// IOUtils.copyBytes(inputStream, outputStream, 4096, true);
|
||||||
}
|
// }
|
||||||
} catch (IOException e) {
|
// } catch (IOException e) {
|
||||||
throw new RuntimeException("Failed to upload file to HDFS: " + e.getMessage(), e);
|
// throw new RuntimeException("Failed to upload file to HDFS: " + e.getMessage(), e);
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
// throw new RuntimeException(e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public void downloadFile(String hdfsEncPath, String localPathWithoutExt, String username) {
|
// public void downloadFile(String hdfsEncPath, String localPathWithoutExt, String username) {
|
||||||
try {
|
// try {
|
||||||
FileSystem fs = HDFSConfig.getHDFS();
|
// FileSystem fs = HDFSConfig.getHDFS();
|
||||||
String encFilePath = localPathWithoutExt + ".enc";
|
// String encFilePath = localPathWithoutExt + ".enc";
|
||||||
fs.copyToLocalFile(new Path(hdfsEncPath), new Path(encFilePath));
|
// fs.copyToLocalFile(new Path(hdfsEncPath), new Path(encFilePath));
|
||||||
|
//
|
||||||
User user = userRepository.findByUsername(username)
|
// User user = userRepository.findByUsername(username)
|
||||||
.orElseThrow(() -> new RuntimeException("User not found"));
|
// .orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
PrivateKey privateKey = RSAKeyUtil.getPrivateKeyFromBytes(user.getPrivateKey());
|
// PrivateKey privateKey = RSAKeyUtil.getPrivateKeyFromBytes(user.getPrivateKey());
|
||||||
|
//
|
||||||
byte[] encryptedFileContent = Files.readAllBytes(Paths.get(encFilePath));
|
// byte[] encryptedFileContent = Files.readAllBytes(Paths.get(encFilePath));
|
||||||
byte[] decryptedFileContent = RSAKeyUtil.decrypt(encryptedFileContent, privateKey);
|
// byte[] decryptedFileContent = RSAKeyUtil.decrypt(encryptedFileContent, privateKey);
|
||||||
|
//
|
||||||
Files.write(Paths.get(localPathWithoutExt), decryptedFileContent);
|
// Files.write(Paths.get(localPathWithoutExt), decryptedFileContent);
|
||||||
Files.deleteIfExists(Paths.get(encFilePath));
|
// Files.deleteIfExists(Paths.get(encFilePath));
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
throw new RuntimeException("Failed to download or decrypt file: " + e.getMessage(), e);
|
// throw new RuntimeException("Failed to download or decrypt file: " + e.getMessage(), e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
public void createFolder(String hdfsPath) {
|
public void createFolder(String hdfsPath) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,83 +1,69 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.services;
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
import java.security.Key;
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
import java.util.Date;
|
import io.jsonwebtoken.*;
|
||||||
import java.util.HashMap;
|
import io.jsonwebtoken.io.Decoders;
|
||||||
import java.util.Map;
|
import io.jsonwebtoken.security.Keys;
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import io.jsonwebtoken.Claims;
|
import java.security.Key;
|
||||||
import io.jsonwebtoken.Jwts;
|
import java.util.Date;
|
||||||
import io.jsonwebtoken.SignatureAlgorithm;
|
import java.util.function.Function;
|
||||||
import io.jsonwebtoken.io.Decoders;
|
|
||||||
import io.jsonwebtoken.security.Keys;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class JwtService {
|
public class JwtService {
|
||||||
|
|
||||||
@Value("${security.jwt.secret-key}")
|
@Value("${security.jwt.secret-key}")
|
||||||
private String secretKey;
|
private String secretKey;
|
||||||
|
|
||||||
@Value("${security.jwt.expiration-time}")
|
@Value("${security.jwt.expiration-time}")
|
||||||
private long jwtExpiration;
|
private long expirationTime;
|
||||||
|
|
||||||
public String extractUsername(String token){
|
private static final String SECRET_KEY = "PPp27xSTfBwOpRn4/AV6gPzQSnQg+Oi80KdWfCcuAHs=";
|
||||||
return extractClaim(token,Claims::getSubject);
|
|
||||||
|
private Key getSigningKey() {
|
||||||
|
byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
|
||||||
|
return Keys.hmacShaKeyFor(keyBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T extractClaim(String token,Function<Claims,T> claimsResolver){
|
public String extractUsername(String token) {
|
||||||
final Claims claims=extractAllClaims(token);
|
return extractClaim(token, Claims::getSubject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date extractExpiration(String token) {
|
||||||
|
return extractClaim(token, Claims::getExpiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
|
||||||
|
Claims claims = Jwts.parserBuilder()
|
||||||
|
.setSigningKey(getSigningKey())
|
||||||
|
.build()
|
||||||
|
.parseClaimsJws(token)
|
||||||
|
.getBody();
|
||||||
return claimsResolver.apply(claims);
|
return claimsResolver.apply(claims);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public String generateToken(UserDetails userDetails) {
|
|
||||||
return generateToken(new HashMap<>(), userDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String generateToken(Map<String, Object> extraClaims, UserDetails userDetails) {
|
|
||||||
return buildToken(extraClaims, userDetails, jwtExpiration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getExpirtationTime(){
|
|
||||||
return jwtExpiration;
|
|
||||||
}
|
|
||||||
private String buildToken(Map<String,Object> extraClaims,UserDetails userDetails,long expiration){
|
|
||||||
|
|
||||||
return Jwts.builder().setClaims(extraClaims).setSubject(userDetails.getUsername())
|
|
||||||
.setIssuedAt(new Date(System.currentTimeMillis()))
|
|
||||||
.setExpiration(new Date(System.currentTimeMillis() + expiration))
|
|
||||||
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
|
|
||||||
.compact();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTokenValid(String token, UserDetails userDetails) {
|
public boolean isTokenValid(String token, UserDetails userDetails) {
|
||||||
final String username = extractUsername(token);
|
final String username = extractUsername(token);
|
||||||
return (username.equals(userDetails.getUsername())) && !isTokenExpired(token);
|
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTokenExpired(String token) {
|
public boolean isTokenExpired(String token) {
|
||||||
return extractExpiration(token).before(new Date());
|
return extractExpiration(token).before(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Date extractExpiration(String token) {
|
public String generateToken(UserDetails userDetails) {
|
||||||
return extractClaim(token, Claims::getExpiration);
|
return Jwts.builder()
|
||||||
|
.setSubject(userDetails.getUsername())
|
||||||
|
.setIssuedAt(new Date())
|
||||||
|
.setExpiration(new Date(System.currentTimeMillis() + expirationTime))
|
||||||
|
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
|
||||||
|
.compact();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Claims extractAllClaims(String token) {
|
public String generateToken(User user) {
|
||||||
return Jwts
|
return generateToken((UserDetails) user);
|
||||||
.parserBuilder()
|
|
||||||
.setSigningKey(getSignInKey())
|
|
||||||
.build()
|
|
||||||
.parseClaimsJws(token)
|
|
||||||
.getBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Key getSignInKey() {
|
|
||||||
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
|
|
||||||
return Keys.hmacShaKeyFor(keyBytes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class KeyCacheService {
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<Long, String> keyCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public void cacheKey(Long userId, String decryptedKey) {
|
||||||
|
keyCache.put(userId, decryptedKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey(Long userId) {
|
||||||
|
return keyCache.get(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearKey(Long userId) {
|
||||||
|
keyCache.remove(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearAllKeys() {
|
||||||
|
keyCache.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// NEED TO IMPLEMENT SAHI SE
|
||||||
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class RateLimiterService {
|
||||||
|
private final ConcurrentHashMap<String, Integer> attempts = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public boolean isBlocked(String ip) {
|
||||||
|
return attempts.getOrDefault(ip, 0) >= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordFailedAttempt(String ip) {
|
||||||
|
attempts.put(ip, attempts.getOrDefault(ip, 0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetAttempts(String ip) {
|
||||||
|
attempts.remove(ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.RefreshToken;
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
|
import com.skycrate.backend.skycrateBackend.repository.RefreshTokenRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class RefreshTokenService {
|
||||||
|
|
||||||
|
private final RefreshTokenRepository refreshTokenRepo;
|
||||||
|
|
||||||
|
@Value("${security.jwt.refresh-expiry-ms:86400000}") //1 day in milliseconds
|
||||||
|
private Long refreshTokenDurationMs;
|
||||||
|
|
||||||
|
public RefreshTokenService(RefreshTokenRepository refreshTokenRepo) {
|
||||||
|
this.refreshTokenRepo = refreshTokenRepo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public RefreshToken createRefreshToken(User user) {
|
||||||
|
refreshTokenRepo.deleteByUser(user);
|
||||||
|
refreshTokenRepo.flush();
|
||||||
|
|
||||||
|
RefreshToken token = new RefreshToken();
|
||||||
|
token.setUser(user);
|
||||||
|
token.setExpiryDate(Instant.now().plusMillis(refreshTokenDurationMs));
|
||||||
|
token.setToken(UUID.randomUUID().toString());
|
||||||
|
return refreshTokenRepo.save(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Optional<RefreshToken> findByToken(String token) {
|
||||||
|
return refreshTokenRepo.findByToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExpired(RefreshToken token) {
|
||||||
|
return token.getExpiryDate().isBefore(Instant.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void deleteByUser(User user) {
|
||||||
|
try {
|
||||||
|
refreshTokenRepo.deleteByUser(user);
|
||||||
|
System.out.println("Successfully deleted refresh tokens for user: " + user.getId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Error deleting refresh tokens for user: " + user.getId() + " - " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void logout(User user) {
|
||||||
|
deleteByUser(user); // This should call the repository method to delete the token
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<RefreshToken> refreshAccessToken(String refreshToken) {
|
||||||
|
return findByToken(refreshToken).filter(token -> !isExpired(token));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
|
import com.skycrate.backend.skycrateBackend.dto.SignupRequest;
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class UserService {
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerUser(SignupRequest request) {
|
||||||
|
if (isPasswordPwned(request.getPassword())) {
|
||||||
|
throw new IllegalArgumentException("Password has been compromised in data breaches.");
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = new User();
|
||||||
|
user.setUsername(request.getUsername());
|
||||||
|
user.setEmail(request.getEmail());
|
||||||
|
user.setPassword(passwordEncoder.encode(request.getPassword()));
|
||||||
|
userRepository.save(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPasswordPwned(String password) {
|
||||||
|
try {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||||
|
byte[] hash = md.digest(password.getBytes());
|
||||||
|
String fullHash = String.format("%040x", new BigInteger(1, hash)).toUpperCase();
|
||||||
|
String prefix = fullHash.substring(0, 5);
|
||||||
|
String suffix = fullHash.substring(5);
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
String response = restTemplate.getForObject("https://api.pwnedpasswords.com/range/" + prefix, String.class);
|
||||||
|
|
||||||
|
return response != null && response.contains(suffix);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false; // If API fails, allow but log in production
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.utils;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
import javax.crypto.spec.*;
|
||||||
|
import java.security.*;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class EncryptionUtil {
|
||||||
|
|
||||||
|
private static final int SALT_LENGTH = 16;
|
||||||
|
private static final int IV_LENGTH = 16;
|
||||||
|
private static final int ITERATIONS = 65536;
|
||||||
|
private static final int KEY_LENGTH = 256;
|
||||||
|
|
||||||
|
private static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
|
||||||
|
private static final String AES_CIPHER = "AES/CBC/PKCS5Padding";
|
||||||
|
private static final String RSA_CIPHER = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
|
||||||
|
|
||||||
|
private static final SecureRandom secureRandom = new SecureRandom();
|
||||||
|
|
||||||
|
// ------------------------ AES ------------------------
|
||||||
|
|
||||||
|
public static byte[] generateSalt() {
|
||||||
|
byte[] salt = new byte[SALT_LENGTH];
|
||||||
|
secureRandom.nextBytes(salt);
|
||||||
|
return salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] generateIv() {
|
||||||
|
byte[] iv = new byte[IV_LENGTH];
|
||||||
|
secureRandom.nextBytes(iv);
|
||||||
|
return iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SecretKey deriveKey(char[] password, byte[] salt) throws Exception {
|
||||||
|
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
|
||||||
|
PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
|
||||||
|
SecretKey tmp = factory.generateSecret(spec);
|
||||||
|
return new SecretKeySpec(tmp.getEncoded(), "AES");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SecretKey generateAESKey() throws Exception {
|
||||||
|
byte[] keyBytes = new byte[KEY_LENGTH / 8]; // 256 bits
|
||||||
|
secureRandom.nextBytes(keyBytes);
|
||||||
|
return new SecretKeySpec(keyBytes, "AES");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SecretKey rebuildAESKey(byte[] keyBytes) {
|
||||||
|
return new SecretKeySpec(keyBytes, "AES");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] encrypt(byte[] plaintext, SecretKey key, byte[] iv) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance(AES_CIPHER);
|
||||||
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
|
||||||
|
return cipher.doFinal(plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] decrypt(byte[] ciphertext, SecretKey key, byte[] iv) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance(AES_CIPHER);
|
||||||
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
|
||||||
|
return cipher.doFinal(ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------ RSA ------------------------
|
||||||
|
|
||||||
|
public static byte[] encryptRSA(byte[] data, PublicKey publicKey) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance(RSA_CIPHER);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
|
return cipher.doFinal(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] decryptRSA(byte[] data, PrivateKey privateKey) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance(RSA_CIPHER);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
|
return cipher.doFinal(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// // --------- Encrypt/decrypt RSA private key using AES derived from password ---------
|
||||||
|
//
|
||||||
|
// public static byte[] encryptPrivateKey(PrivateKey privateKey, String password, byte[] salt, byte[] iv) throws Exception {
|
||||||
|
// SecretKey aesKey = deriveKey(password.toCharArray(), salt);
|
||||||
|
// return encrypt(privateKey.getEncoded(), aesKey, iv);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static byte[] decryptPrivateKey(byte[] encryptedPrivateKey, String password, byte[] salt, byte[] iv) throws Exception {
|
||||||
|
// SecretKey aesKey = deriveKey(password.toCharArray(), salt);
|
||||||
|
// return decrypt(encryptedPrivateKey, aesKey, iv);
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -9,31 +9,31 @@ import java.security.spec.X509EncodedKeySpec;
|
|||||||
|
|
||||||
public class KeyUtil {
|
public class KeyUtil {
|
||||||
|
|
||||||
public static void generateAndStoreKeyPair(String username) throws Exception {
|
// public static void generateAndStoreKeyPair(String username) throws Exception {
|
||||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
// KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||||
keyPairGenerator.initialize(2048); // Key size
|
// keyPairGenerator.initialize(2048); // Key size
|
||||||
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
// KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
||||||
|
//
|
||||||
// Store the public key
|
// // Store the public key
|
||||||
Path publicKeyPath = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_public.key");
|
// Path publicKeyPath = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_public.key");
|
||||||
Files.write(publicKeyPath, keyPair.getPublic().getEncoded());
|
// Files.write(publicKeyPath, keyPair.getPublic().getEncoded());
|
||||||
|
//
|
||||||
// Store the private key
|
// // Store the private key
|
||||||
Path privateKeyPath = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_private.key");
|
// Path privateKeyPath = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_private.key");
|
||||||
Files.write(privateKeyPath, keyPair.getPrivate().getEncoded());
|
// Files.write(privateKeyPath, keyPair.getPrivate().getEncoded());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static PublicKey getPublicKeyForUser(String username) throws Exception {
|
// public static PublicKey getPublicKeyForUser(String username) throws Exception {
|
||||||
Path path = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_public.key");
|
// Path path = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_public.key");
|
||||||
byte[] bytes = Files.readAllBytes(path);
|
// byte[] bytes = Files.readAllBytes(path);
|
||||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
|
// X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
|
||||||
return KeyFactory.getInstance("RSA").generatePublic(keySpec);
|
// return KeyFactory.getInstance("RSA").generatePublic(keySpec);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static PrivateKey getPrivateKeyForUser(String username) throws Exception {
|
// public static PrivateKey getPrivateKeyForUser(String username) throws Exception {
|
||||||
Path path = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_private.key");
|
// Path path = Paths.get("C:\\Users\\sonal\\OneDrive\\Desktop\\SkyCrate\\Skycrate\\keys", username + "_private.key");
|
||||||
byte[] bytes = Files.readAllBytes(path);
|
// byte[] bytes = Files.readAllBytes(path);
|
||||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
|
// PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
|
||||||
return KeyFactory.getInstance("RSA").generatePrivate(keySpec);
|
// return KeyFactory.getInstance("RSA").generatePrivate(keySpec);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
@@ -29,52 +29,45 @@ public class RSAKeyUtil {
|
|||||||
return keyFactory.generatePrivate(spec);
|
return keyFactory.generatePrivate(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shorthand decode aliases
|
||||||
|
public static PublicKey decodePublicKey(byte[] publicKeyBytes) throws Exception {
|
||||||
|
return getPublicKeyFromBytes(publicKeyBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PrivateKey decodePrivateKey(byte[] privateKeyBytes) throws Exception {
|
||||||
|
return getPrivateKeyFromBytes(privateKeyBytes);
|
||||||
|
}
|
||||||
|
|
||||||
// Encrypt data using RSA (with padding)
|
// Encrypt data using RSA (with padding)
|
||||||
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
|
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
|
||||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // Specify padding
|
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
return cipher.doFinal(data);
|
return cipher.doFinal(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt data using RSA (with padding)
|
// Decrypt data using RSA (with padding)
|
||||||
public static byte[] decrypt(byte[] encryptedData, PrivateKey privateKey) throws Exception {
|
public static byte[] decrypt(byte[] encryptedData, PrivateKey privateKey) throws Exception {
|
||||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // Specify padding
|
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
return cipher.doFinal(encryptedData);
|
return cipher.doFinal(encryptedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate AES Key (128, 192, or 256 bits)
|
// // AES key generation
|
||||||
public static SecretKey generateAESKey(int keySize) throws NoSuchAlgorithmException {
|
// public static SecretKey generateAESKey(int keySize) throws NoSuchAlgorithmException {
|
||||||
if (keySize != 128 && keySize != 192 && keySize != 256) {
|
// if (keySize != 128 && keySize != 192 && keySize != 256) {
|
||||||
throw new IllegalArgumentException("Invalid AES key size. Must be 128, 192, or 256 bits.");
|
// throw new IllegalArgumentException("Invalid AES key size. Must be 128, 192, or 256 bits.");
|
||||||
}
|
|
||||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
|
||||||
keyGenerator.init(keySize); // Specify the key size
|
|
||||||
return keyGenerator.generateKey();
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// // Encrypt AES Key using RSA
|
|
||||||
// public static byte[] encryptAESKey(SecretKey aesKey, PublicKey publicKey) throws Exception {
|
|
||||||
// return encrypt(aesKey.getEncoded(), publicKey); // Encrypt the AES key using RSA
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Decrypt AES Key using RSA
|
|
||||||
// public static SecretKey decryptAESKey(byte[] encryptedAESKey, PrivateKey privateKey, int keySize) throws Exception {
|
|
||||||
// byte[] decryptedKey = decrypt(encryptedAESKey, privateKey); // Decrypt with RSA
|
|
||||||
// // Ensure that the decrypted key length matches the expected AES key size
|
|
||||||
// if (decryptedKey.length != keySize / 8) {
|
|
||||||
// throw new IllegalArgumentException("Decrypted key size does not match expected AES key size.");
|
|
||||||
// }
|
// }
|
||||||
// return new SecretKeySpec(decryptedKey, 0, decryptedKey.length, "AES"); // Convert to AES Key
|
// KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
||||||
|
// keyGenerator.init(keySize);
|
||||||
|
// return keyGenerator.generateKey();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static byte[] encryptAESKey(SecretKey aesKey, PublicKey publicKey) throws Exception {
|
||||||
|
// return encrypt(aesKey.getEncoded(), publicKey);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static SecretKey decryptAESKey(byte[] encryptedAESKey, PrivateKey privateKey, int keySize) throws Exception {
|
||||||
|
// byte[] decryptedKey = decrypt(encryptedAESKey, privateKey);
|
||||||
|
// return new SecretKeySpec(decryptedKey, 0, decryptedKey.length, "AES");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public static byte[] encryptAESKey(SecretKey aesKey, PublicKey publicKey) throws Exception {
|
|
||||||
return encrypt(aesKey.getEncoded(), publicKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SecretKey decryptAESKey(byte[] encryptedAESKey, PrivateKey privateKey, int keySize) throws Exception {
|
|
||||||
byte[] decryptedKey = decrypt(encryptedAESKey, privateKey);
|
|
||||||
return new SecretKeySpec(decryptedKey, 0, decryptedKey.length, "AES");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
server:
|
||||||
|
port: 8443
|
||||||
|
ssl:
|
||||||
|
enabled: true
|
||||||
|
key-store: classpath:keystore.p12
|
||||||
|
key-store-password: changeit
|
||||||
|
key-store-type: PKCS12
|
||||||
|
key-alias: tomcat
|
||||||
@@ -5,13 +5,13 @@ spring.servlet.multipart.max-request-size=1000MB
|
|||||||
|
|
||||||
spring.servlet.multipart.enabled=true
|
spring.servlet.multipart.enabled=true
|
||||||
|
|
||||||
security.jwt.secret-key=3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567c272e007b
|
security.jwt.secret-key=${JWT_SECRET}
|
||||||
security.jwt.expiration-time=3600000
|
security.jwt.expiration-time=3600000
|
||||||
|
|
||||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
|
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
|
||||||
spring.datasource.username=skycrateDB
|
spring.datasource.username=${DB_USERNAME}
|
||||||
spring.datasource.password=${MYSQL_PASSWORD}
|
spring.datasource.password=${DB_PASSWORD}
|
||||||
spring.datasource.url=jdbc:mysql://db:3306/skycrate
|
spring.datasource.url=jdbc:mysql://${DB_URI}/${DB_NAME}
|
||||||
|
|
||||||
spring.jpa.hibernate.ddl-auto=update
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
spring.jpa.show-sql=true
|
spring.jpa.show-sql=true
|
||||||
@@ -19,26 +19,20 @@ spring.jpa.properties.hibernate.format_sql=true
|
|||||||
spring.jpa.open-in-view=false
|
spring.jpa.open-in-view=false
|
||||||
logging.level.org.springframework.security.config.annotation.authentication.configuration.InitializeUserDetailsBeanManagerConfigurer=ERROR
|
logging.level.org.springframework.security.config.annotation.authentication.configuration.InitializeUserDetailsBeanManagerConfigurer=ERROR
|
||||||
|
|
||||||
server.port=8081
|
server.port=8080
|
||||||
|
|
||||||
|
server.ssl.enabled=true
|
||||||
|
server.ssl.key-store=classpath:keystore.p12
|
||||||
|
server.ssl.key-store-password=${SSL_PASSWORD}
|
||||||
|
server.ssl.key-store-type=PKCS12
|
||||||
|
server.ssl.key-alias=skycrateSSL
|
||||||
|
|
||||||
|
management.endpoints.web.exposure.include=*
|
||||||
|
management.endpoint.health.show-details=always
|
||||||
|
management.endpoints.enabled-by-default=true
|
||||||
|
|
||||||
|
# Allow unauthenticated access
|
||||||
# spring.application.name=skycrateBackend
|
#management.server.port=8080
|
||||||
|
#management.server.ssl.enabled=false
|
||||||
# spring.servlet.multipart.max-file-size=1000MB
|
#management.endpoints.web.base-path=/actuator
|
||||||
# spring.servlet.multipart.max-request-size=1000MB
|
#management.endpoints.web.exposure.include=*
|
||||||
|
|
||||||
# security.jwt.secret-key=3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567c272e007b
|
|
||||||
# security.jwt.expiration-time=3600000
|
|
||||||
|
|
||||||
# spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
|
|
||||||
# spring.datasource.username=root
|
|
||||||
# spring.datasource.password=sqlsys
|
|
||||||
# spring.datasource.url=jdbc:mysql://localhost:3306/skycrate
|
|
||||||
|
|
||||||
# spring.jpa.hibernate.ddl-auto=update
|
|
||||||
# spring.jpa.show-sql=true
|
|
||||||
# spring.jpa.properties.hibernate.format_sql=true
|
|
||||||
|
|
||||||
# server.port=8081
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
GENERATE USING: keytool -genkeypair -alias skycrateSSL -keyalg RSA -keysize 4096 -keystore keystore.p12 -storetype PKCS12 -validity 3650 -dname "CN=localhost, OU=Skycrate, O=Skycrate, C=India"
|
||||||
Reference in New Issue
Block a user