From fda27a5324e9390ceff6ad5214539ffbbe07c344 Mon Sep 17 00:00:00 2001 From: raresc4 Date: Sat, 9 Nov 2024 01:05:46 +0200 Subject: [PATCH 1/6] added controllers for login, data models and services --- pom.xml | 9 +- users-service/pom.xml | 88 ++++++++++++++++++ .../src/main/java/com/stackbytes/Main.java | 11 +++ .../controllers/UserController.java | 34 +++++++ .../java/com/stackbytes/models/LoginData.java | 11 +++ .../com/stackbytes/models/ResponseJson.java | 13 +++ .../main/java/com/stackbytes/models/User.java | 31 +++++++ .../models/UsersLoginResponseDto.java | 21 +++++ .../services/BouncyCastleSetup.java | 11 +++ .../stackbytes/services/GPGKeyGenerator.java | 57 ++++++++++++ .../stackbytes/services/GetProperties.java | 22 +++++ .../java/com/stackbytes/services/JwtUtil.java | 32 +++++++ .../stackbytes/services/SecurityConfig.java | 18 ++++ .../com/stackbytes/services/UserService.java | 90 +++++++++++++++++++ 14 files changed, 440 insertions(+), 8 deletions(-) create mode 100644 users-service/pom.xml create mode 100644 users-service/src/main/java/com/stackbytes/Main.java create mode 100644 users-service/src/main/java/com/stackbytes/controllers/UserController.java create mode 100644 users-service/src/main/java/com/stackbytes/models/LoginData.java create mode 100644 users-service/src/main/java/com/stackbytes/models/ResponseJson.java create mode 100644 users-service/src/main/java/com/stackbytes/models/User.java create mode 100644 users-service/src/main/java/com/stackbytes/models/UsersLoginResponseDto.java create mode 100644 users-service/src/main/java/com/stackbytes/services/BouncyCastleSetup.java create mode 100644 users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java create mode 100644 users-service/src/main/java/com/stackbytes/services/GetProperties.java create mode 100644 users-service/src/main/java/com/stackbytes/services/JwtUtil.java create mode 100644 users-service/src/main/java/com/stackbytes/services/SecurityConfig.java create mode 100644 users-service/src/main/java/com/stackbytes/services/UserService.java diff --git a/pom.xml b/pom.xml index daafa7d..de05254 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,7 @@ prescription-service + users-service @@ -42,10 +43,6 @@ org.springframework.boot spring-boot-starter-data-mongodb - - org.springframework.boot - spring-boot-starter-data-redis - org.springframework.boot spring-boot-starter-web @@ -54,10 +51,6 @@ io.micrometer micrometer-tracing-bridge-brave - - io.zipkin.reporter2 - zipkin-reporter-brave - org.projectlombok diff --git a/users-service/pom.xml b/users-service/pom.xml new file mode 100644 index 0000000..5a2c625 --- /dev/null +++ b/users-service/pom.xml @@ -0,0 +1,88 @@ + + + 4.0.0 + + + com.stackbytes + mediva-backend + 0.0.1-SNAPSHOT + + + org.example + users-service + + + 21 + 21 + UTF-8 + + + + + de.svenkubiak + jBCrypt + 0.4 + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-web + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.springframework.security + spring-security-jwt + 1.1.1.RELEASE + + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + javax.xml.bind + jaxb-api + 2.3.1 + + + + + org.glassfish.jaxb + jaxb-runtime + 2.3.1 + + + + org.bouncycastle + bcprov-jdk15on + 1.70 + + + + + org.bouncycastle + bcpg-jdk15on + 1.70 + + + com.fasterxml.jackson.core + jackson-core + 2.18.1 + + + \ No newline at end of file diff --git a/users-service/src/main/java/com/stackbytes/Main.java b/users-service/src/main/java/com/stackbytes/Main.java new file mode 100644 index 0000000..050b4aa --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/Main.java @@ -0,0 +1,11 @@ +package com.stackbytes; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Main { + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} \ No newline at end of file diff --git a/users-service/src/main/java/com/stackbytes/controllers/UserController.java b/users-service/src/main/java/com/stackbytes/controllers/UserController.java new file mode 100644 index 0000000..2f6c0a0 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/controllers/UserController.java @@ -0,0 +1,34 @@ +package com.stackbytes.controllers; + +import com.stackbytes.models.LoginData; +import com.stackbytes.models.ResponseJson; +import com.stackbytes.services.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import com.stackbytes.models.User; + +@RestController() +@RequestMapping("/users") +public class UserController { + @Autowired + private final UserService userService; + public UserController(UserService userService) { + this.userService = userService; + } + @CrossOrigin + @PostMapping("/login") + public ResponseJson loginUser(@RequestBody LoginData loginData) { + return userService.loginUser(loginData); + } + @CrossOrigin + @PostMapping("/register") + public ResponseJson registerUser(@RequestBody User user) { + return userService.registerUser(user); + } + @CrossOrigin + @GetMapping("/test") + public String test() { + return userService.test(); + } +} diff --git a/users-service/src/main/java/com/stackbytes/models/LoginData.java b/users-service/src/main/java/com/stackbytes/models/LoginData.java new file mode 100644 index 0000000..dadafdf --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/models/LoginData.java @@ -0,0 +1,11 @@ +package com.stackbytes.models; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class LoginData { + private String email; + private String password; +} diff --git a/users-service/src/main/java/com/stackbytes/models/ResponseJson.java b/users-service/src/main/java/com/stackbytes/models/ResponseJson.java new file mode 100644 index 0000000..c3cbb16 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/models/ResponseJson.java @@ -0,0 +1,13 @@ +package com.stackbytes.models; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class ResponseJson { + private int code; + private boolean status; + private String message; + private String token; +} diff --git a/users-service/src/main/java/com/stackbytes/models/User.java b/users-service/src/main/java/com/stackbytes/models/User.java new file mode 100644 index 0000000..9973baf --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/models/User.java @@ -0,0 +1,31 @@ +package com.stackbytes.models; + +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +import java.util.List; + +@Document(collection = "users") +@Builder +@Getter +@Setter +@Data +public class User { + @Id + private String id; + private List illnesses; + private String fullName; + private String username; + private String email; + private String password; + private boolean medic; + private String gpg; + private List doctors; + private List symptoms; + private List appointments; + private List groups; +} diff --git a/users-service/src/main/java/com/stackbytes/models/UsersLoginResponseDto.java b/users-service/src/main/java/com/stackbytes/models/UsersLoginResponseDto.java new file mode 100644 index 0000000..002fe76 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/models/UsersLoginResponseDto.java @@ -0,0 +1,21 @@ +package com.stackbytes.models; + +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.ToString; + +import java.util.HashMap; +import java.util.Hashtable; + +@Builder +@Getter +@Data +@ToString +public class UsersLoginResponseDto { + private String id; + private String email; + private String username; + private boolean isDoctor; + private String fullName; +} \ No newline at end of file diff --git a/users-service/src/main/java/com/stackbytes/services/BouncyCastleSetup.java b/users-service/src/main/java/com/stackbytes/services/BouncyCastleSetup.java new file mode 100644 index 0000000..451b157 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/services/BouncyCastleSetup.java @@ -0,0 +1,11 @@ +package com.stackbytes.services; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import java.security.Security; + +public class BouncyCastleSetup { + public static void setup() { + Security.addProvider(new BouncyCastleProvider()); + } +} diff --git a/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java b/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java new file mode 100644 index 0000000..1e31e26 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java @@ -0,0 +1,57 @@ +package com.stackbytes.services; + +import jakarta.annotation.PostConstruct; +import org.bouncycastle.bcpg.HashAlgorithmTags; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.*; +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; +import org.bouncycastle.openpgp.operator.PGPDigestCalculator; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.springframework.context.annotation.Configuration; + +import javax.crypto.Cipher; +import java.security.*; +import java.util.Base64; +import java.util.Date; +import java.util.HashMap; + +@Configuration +public class GPGKeyGenerator { + @PostConstruct + public void init() { + BouncyCastleSetup.setup(); + } + private String encryptBase64String(String base64String, PublicKey publicKey) throws Exception { + byte[] dataToEncrypt = Base64.getDecoder().decode(base64String); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + byte[] encryptedData = cipher.doFinal(dataToEncrypt); + return Base64.getEncoder().encodeToString(encryptedData); + } + public HashMap generateKey(String identity, String passphrase) { + try { + HashMap keyPair = new HashMap<>(); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048, new SecureRandom()); + KeyPair keyPairRSA = keyPairGenerator.generateKeyPair(); + PGPKeyPair pgpKeyPair = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, keyPairRSA, new Date()); + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PBESecretKeyEncryptor secretKeyEncryptor = new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc).setProvider("BC").build(passphrase.toCharArray()); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, pgpKeyPair, identity, sha1Calc, null, null, new JcaPGPContentSignerBuilder(pgpKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1), secretKeyEncryptor); + String initialPublicKey = keyRingGen.generatePublicKeyRing().getEncoded().toString(); + String publicKey = Base64.getEncoder().encodeToString(initialPublicKey.getBytes()); + String privateKey = Base64.getEncoder().encodeToString(keyRingGen.generateSecretKeyRing().getEncoded()); + String encryptedPrivateKey = encryptBase64String(privateKey, keyPairRSA.getPublic()); + keyPair.put("privateKey", encryptedPrivateKey); + keyPair.put("publicKey", publicKey); + return keyPair; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/users-service/src/main/java/com/stackbytes/services/GetProperties.java b/users-service/src/main/java/com/stackbytes/services/GetProperties.java new file mode 100644 index 0000000..4881686 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/services/GetProperties.java @@ -0,0 +1,22 @@ +package com.stackbytes.services; + +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import java.io.FileInputStream; +import java.util.Properties; + +@Configuration +public class GetProperties { + public String getProperties(String key) { + Properties prop = new Properties(); + try { + prop.load(new FileInputStream("users-service/src/main/resources/application.properties")); + String DB_URL = prop.getProperty(key); + return DB_URL; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/users-service/src/main/java/com/stackbytes/services/JwtUtil.java b/users-service/src/main/java/com/stackbytes/services/JwtUtil.java new file mode 100644 index 0000000..acb9fe9 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/services/JwtUtil.java @@ -0,0 +1,32 @@ +package com.stackbytes.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Configuration +public class JwtUtil { + @Autowired + private GetProperties getProperties; + public String getToken(String jwtHeader) { + String key = getProperties.getProperties("jwt.secret"); + Map claims = new HashMap<>(); + try { + return Jwts.builder() + .setClaims(claims) + .setSubject(jwtHeader.toString()) + .setIssuedAt(new Date(System.currentTimeMillis())) + .signWith(SignatureAlgorithm.HS256, key) + .compact(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/users-service/src/main/java/com/stackbytes/services/SecurityConfig.java b/users-service/src/main/java/com/stackbytes/services/SecurityConfig.java new file mode 100644 index 0000000..750bda3 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/services/SecurityConfig.java @@ -0,0 +1,18 @@ +package com.stackbytes.services; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .csrf(csrf -> csrf.disable()); + return http.build(); + } +} diff --git a/users-service/src/main/java/com/stackbytes/services/UserService.java b/users-service/src/main/java/com/stackbytes/services/UserService.java new file mode 100644 index 0000000..c1a5645 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/services/UserService.java @@ -0,0 +1,90 @@ +package com.stackbytes.services; + +import brave.Response; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.stackbytes.models.LoginData; +import com.stackbytes.models.ResponseJson; +import com.stackbytes.models.User; +import com.stackbytes.models.UsersLoginResponseDto; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Service; + +import org.mindrot.jbcrypt.BCrypt; + +import java.util.HashMap; + +@Service +public class UserService { + private final MongoTemplate mongoTemplate; + @Autowired + private GPGKeyGenerator gpgKeyGenerator; + @Autowired + private JwtUtil jwtUtil; + @Autowired + private GetProperties getProperties; + private final ObjectMapper objectMapper; + public UserService(MongoTemplate mongoTemplate, ObjectMapper objectMapper) { + this.mongoTemplate = mongoTemplate; + this.objectMapper = objectMapper; + } + public String test() { + HashMap response = gpgKeyGenerator.generateKey("test", "test"); + return "public key : " + response.get("publicKey") + " private key : " + response.get("privateKey"); + } + public ResponseJson loginUser(LoginData loginData) { + if (loginData.getEmail() == null || loginData.getPassword() == null) { + return ResponseJson.builder().code(404).status(false).message("Email or password cannot be null").build(); + } + try { + User user = mongoTemplate.findOne(new Query(Criteria.where("email").is(loginData.getEmail())), User.class); + if (user == null) { + return ResponseJson.builder().code(404).status(false).message("User not found").build(); + } + if (BCrypt.checkpw(loginData.getPassword(), user.getPassword())) { + UsersLoginResponseDto responseDto = UsersLoginResponseDto.builder() + .id(user.getId()) + .email(user.getEmail()) + .username(user.getUsername()) + .isDoctor(user.isMedic()) + .fullName(user.getFullName()) + .build(); + String jsonStringTokenContent = objectMapper.writeValueAsString(responseDto); + String token = jwtUtil.getToken(jsonStringTokenContent); + System.out.println(jsonStringTokenContent); + return ResponseJson.builder() + .code(200) + .status(true) + .message("User logged in") + .token(token) + .build(); + } else { + return ResponseJson.builder().code(404).status(false).message("Incorrect password").build(); + } + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); + } + } + public ResponseJson registerUser(User user){ + if(user == null){ + return ResponseJson.builder().code(404).status(false).message("User cannot be null").build(); + } + try { + User userExists = mongoTemplate.findOne(new Query(Criteria.where("email").is(user.getEmail())), User.class); + if (userExists != null) { + return ResponseJson.builder().code(404).status(false).message("User already exists").build(); + } + user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt())); + try { + mongoTemplate.save(user); + return ResponseJson.builder().code(200).status(true).message("User registered").build(); + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); + } + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); + } + } +} From 23848de365d730ac5593ede381824807cd8708e8 Mon Sep 17 00:00:00 2001 From: raresc4 Date: Sat, 9 Nov 2024 14:42:45 +0200 Subject: [PATCH 2/6] worked on gpg --- .../com/stackbytes/models/ResponseJson.java | 3 + .../main/java/com/stackbytes/models/User.java | 3 +- .../stackbytes/services/GPGKeyGenerator.java | 68 ++++++++++++++++--- .../com/stackbytes/services/UserService.java | 21 +++++- 4 files changed, 85 insertions(+), 10 deletions(-) diff --git a/users-service/src/main/java/com/stackbytes/models/ResponseJson.java b/users-service/src/main/java/com/stackbytes/models/ResponseJson.java index c3cbb16..665a3cd 100644 --- a/users-service/src/main/java/com/stackbytes/models/ResponseJson.java +++ b/users-service/src/main/java/com/stackbytes/models/ResponseJson.java @@ -3,6 +3,8 @@ import lombok.Builder; import lombok.Getter; +import java.util.HashMap; + @Builder @Getter public class ResponseJson { @@ -10,4 +12,5 @@ public class ResponseJson { private boolean status; private String message; private String token; + private HashMap gpg; } diff --git a/users-service/src/main/java/com/stackbytes/models/User.java b/users-service/src/main/java/com/stackbytes/models/User.java index 9973baf..3680b4c 100644 --- a/users-service/src/main/java/com/stackbytes/models/User.java +++ b/users-service/src/main/java/com/stackbytes/models/User.java @@ -7,6 +7,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; +import java.util.HashMap; import java.util.List; @Document(collection = "users") @@ -23,7 +24,7 @@ public class User { private String email; private String password; private boolean medic; - private String gpg; + private HashMap gpg; private List doctors; private List symptoms; private List appointments; diff --git a/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java b/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java index 1e31e26..e517a5c 100644 --- a/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java +++ b/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java @@ -11,9 +11,16 @@ import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; import java.security.*; import java.util.Base64; import java.util.Date; @@ -21,17 +28,61 @@ @Configuration public class GPGKeyGenerator { + @Autowired + private GetProperties getProperties; @PostConstruct public void init() { BouncyCastleSetup.setup(); } - private String encryptBase64String(String base64String, PublicKey publicKey) throws Exception { - byte[] dataToEncrypt = Base64.getDecoder().decode(base64String); - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.ENCRYPT_MODE, publicKey); - byte[] encryptedData = cipher.doFinal(dataToEncrypt); - return Base64.getEncoder().encodeToString(encryptedData); + + private SecretKey generateAESKeyFromInput(String input) throws Exception { + // Convert the input string to a byte array (use it as salt) + byte[] salt = Base64.getDecoder().decode(input); + String secret = getProperties.getProperties("jwt.secret"); + // Define parameters for PBKDF2 + String password = secret; // Use a fixed password or other secret input + int iterationCount = 65536; // Number of PBKDF2 iterations + int keyLength = 256; // AES-256 + + // Derive the AES key using PBKDF2 + PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterationCount, keyLength); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + byte[] keyBytes = keyFactory.generateSecret(spec).getEncoded(); + + // Convert derived key bytes to AES SecretKey + return new SecretKeySpec(keyBytes, "AES"); } + + public HashMap encryptPrivateKeyWithAES(String privateKey, PublicKey rsaPublicKey) throws Exception { + // Generate a random AES key + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); // AES-256 + SecretKey aesKey = generateAESKeyFromInput(getProperties.getProperties("aes_key")); + + // Encrypt the private key with AES + Cipher aesCipher = Cipher.getInstance("AES"); + aesCipher.init(Cipher.ENCRYPT_MODE, aesKey); + byte[] encryptedPrivateKey = aesCipher.doFinal(privateKey.getBytes(StandardCharsets.UTF_8)); + +// // Encrypt the AES key with RSA +// Cipher rsaCipher = Cipher.getInstance("RSA"); +// rsaCipher.init(Cipher.WRAP_MODE, rsaPublicKey); +// byte[] encryptedAESKey = rsaCipher.wrap(aesKey); + + // Encode both encrypted AES key and private key as Base64 strings + HashMap encryptedKeys = new HashMap<>(); + encryptedKeys.put("encryptedPrivateKey", Base64.getEncoder().encodeToString(encryptedPrivateKey)); + encryptedKeys.put("AESKey", Base64.getEncoder().encodeToString(aesKey.getEncoded())); + return encryptedKeys; + } + +// private String encryptBase64String(String base64String, PublicKey publicKey) throws Exception { +// byte[] dataToEncrypt = Base64.getDecoder().decode(base64String); +// Cipher cipher = Cipher.getInstance("RSA"); +// cipher.init(Cipher.ENCRYPT_MODE, publicKey); +// byte[] encryptedData = cipher.doFinal(dataToEncrypt); +// return Base64.getEncoder().encodeToString(encryptedData); +// } public HashMap generateKey(String identity, String passphrase) { try { HashMap keyPair = new HashMap<>(); @@ -45,8 +96,9 @@ public HashMap generateKey(String identity, String passphrase) { String initialPublicKey = keyRingGen.generatePublicKeyRing().getEncoded().toString(); String publicKey = Base64.getEncoder().encodeToString(initialPublicKey.getBytes()); String privateKey = Base64.getEncoder().encodeToString(keyRingGen.generateSecretKeyRing().getEncoded()); - String encryptedPrivateKey = encryptBase64String(privateKey, keyPairRSA.getPublic()); - keyPair.put("privateKey", encryptedPrivateKey); + HashMap encryptedPrivateKey = encryptPrivateKeyWithAES(privateKey, keyPairRSA.getPublic()); + keyPair.put("privateKey", encryptedPrivateKey.get("encryptedPrivateKey")); + keyPair.put("AESKey", encryptedPrivateKey.get("AESKey")); keyPair.put("publicKey", publicKey); return keyPair; } catch (Exception e) { diff --git a/users-service/src/main/java/com/stackbytes/services/UserService.java b/users-service/src/main/java/com/stackbytes/services/UserService.java index c1a5645..91f457c 100644 --- a/users-service/src/main/java/com/stackbytes/services/UserService.java +++ b/users-service/src/main/java/com/stackbytes/services/UserService.java @@ -30,9 +30,28 @@ public UserService(MongoTemplate mongoTemplate, ObjectMapper objectMapper) { this.mongoTemplate = mongoTemplate; this.objectMapper = objectMapper; } + public ResponseJson verifyMedic(User user) { + if(user == null){ + return ResponseJson.builder().code(404).status(false).message("User cannot be null").build(); + } + try { + User userExists = mongoTemplate.findOne(new Query(Criteria.where("email").is(user.getEmail())), User.class); + if (userExists == null) { + return ResponseJson.builder().code(404).status(false).message("User not found").build(); + } + if (userExists.isMedic()) { + HashMap gpg = userExists.getGpg(); + return ResponseJson.builder().code(200).status(true).message("User is a medic").gpg(gpg).build(); + } else { + return ResponseJson.builder().code(404).status(false).message("User is not a medic").build(); + } + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); + } + } public String test() { HashMap response = gpgKeyGenerator.generateKey("test", "test"); - return "public key : " + response.get("publicKey") + " private key : " + response.get("privateKey"); + return "public key : " + response.get("publicKey") + "\nprivate key : " + response.get("privateKey") + "\nAESKey : " + response.get("AESKey"); } public ResponseJson loginUser(LoginData loginData) { if (loginData.getEmail() == null || loginData.getPassword() == null) { From 1e6277a4951e85c5fbac11dac6b1af3845c22201 Mon Sep 17 00:00:00 2001 From: raresc4 Date: Sat, 9 Nov 2024 22:47:21 +0200 Subject: [PATCH 3/6] fixed everything --- .../com/stackbytes/models/ContactInfo.java | 14 +++ .../java/com/stackbytes/models/Medic.java | 33 +++++ .../stackbytes/models/RegisterRequestDto.java | 13 ++ .../main/java/com/stackbytes/models/User.java | 19 +-- .../models/UsersLoginResponseDto.java | 21 ---- .../com/stackbytes/services/UserService.java | 119 ++++++++++-------- 6 files changed, 137 insertions(+), 82 deletions(-) create mode 100644 users-service/src/main/java/com/stackbytes/models/ContactInfo.java create mode 100644 users-service/src/main/java/com/stackbytes/models/Medic.java create mode 100644 users-service/src/main/java/com/stackbytes/models/RegisterRequestDto.java delete mode 100644 users-service/src/main/java/com/stackbytes/models/UsersLoginResponseDto.java diff --git a/users-service/src/main/java/com/stackbytes/models/ContactInfo.java b/users-service/src/main/java/com/stackbytes/models/ContactInfo.java new file mode 100644 index 0000000..b2aab0b --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/models/ContactInfo.java @@ -0,0 +1,14 @@ +package com.stackbytes.models; + +import lombok.Builder; +import lombok.Data; +import lombok.Getter; + +@Builder +@Getter +@Data +public class ContactInfo { + private String phone; + private String email; + private String address; +} diff --git a/users-service/src/main/java/com/stackbytes/models/Medic.java b/users-service/src/main/java/com/stackbytes/models/Medic.java new file mode 100644 index 0000000..1e12c83 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/models/Medic.java @@ -0,0 +1,33 @@ +package com.stackbytes.models; + +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; + +@Document(collection = "medics") +@Data +@Builder +@Getter +public class Medic { + @Id + private String id; + private String medicalId; + private String password; + private Date activeSince; + private String speciality; + private String grade; + private HashMap gpg; + private String workPlace; + private double ratings; + private String bio; + private ContactInfo contactInfo; + private List userId; + private Date createdAt; + private Date updatedAt; +} diff --git a/users-service/src/main/java/com/stackbytes/models/RegisterRequestDto.java b/users-service/src/main/java/com/stackbytes/models/RegisterRequestDto.java new file mode 100644 index 0000000..79f9358 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/models/RegisterRequestDto.java @@ -0,0 +1,13 @@ +package com.stackbytes.models; + +import lombok.Builder; +import lombok.Data; +import lombok.Getter; + +@Builder +@Data +@Getter +public class RegisterRequestDto { + private User user; + private Medic medic; +} diff --git a/users-service/src/main/java/com/stackbytes/models/User.java b/users-service/src/main/java/com/stackbytes/models/User.java index 3680b4c..1ce90c9 100644 --- a/users-service/src/main/java/com/stackbytes/models/User.java +++ b/users-service/src/main/java/com/stackbytes/models/User.java @@ -6,7 +6,9 @@ import lombok.Setter; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.scheduling.support.SimpleTriggerContext; +import java.util.Date; import java.util.HashMap; import java.util.List; @@ -18,15 +20,14 @@ public class User { @Id private String id; - private List illnesses; - private String fullName; - private String username; + private String username; private String email; private String password; - private boolean medic; - private HashMap gpg; - private List doctors; - private List symptoms; - private List appointments; - private List groups; + private String fullName; + private String phone; + private String avatar; + private Medic medic; + private List doctorsId; + private Date createdAt; + private Date updatedAt; } diff --git a/users-service/src/main/java/com/stackbytes/models/UsersLoginResponseDto.java b/users-service/src/main/java/com/stackbytes/models/UsersLoginResponseDto.java deleted file mode 100644 index 002fe76..0000000 --- a/users-service/src/main/java/com/stackbytes/models/UsersLoginResponseDto.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.stackbytes.models; - -import lombok.Builder; -import lombok.Data; -import lombok.Getter; -import lombok.ToString; - -import java.util.HashMap; -import java.util.Hashtable; - -@Builder -@Getter -@Data -@ToString -public class UsersLoginResponseDto { - private String id; - private String email; - private String username; - private boolean isDoctor; - private String fullName; -} \ No newline at end of file diff --git a/users-service/src/main/java/com/stackbytes/services/UserService.java b/users-service/src/main/java/com/stackbytes/services/UserService.java index 91f457c..2191585 100644 --- a/users-service/src/main/java/com/stackbytes/services/UserService.java +++ b/users-service/src/main/java/com/stackbytes/services/UserService.java @@ -1,11 +1,7 @@ package com.stackbytes.services; -import brave.Response; import com.fasterxml.jackson.databind.ObjectMapper; -import com.stackbytes.models.LoginData; -import com.stackbytes.models.ResponseJson; -import com.stackbytes.models.User; -import com.stackbytes.models.UsersLoginResponseDto; +import com.stackbytes.models.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; @@ -14,6 +10,7 @@ import org.mindrot.jbcrypt.BCrypt; +import java.util.Date; import java.util.HashMap; @Service @@ -30,21 +27,18 @@ public UserService(MongoTemplate mongoTemplate, ObjectMapper objectMapper) { this.mongoTemplate = mongoTemplate; this.objectMapper = objectMapper; } - public ResponseJson verifyMedic(User user) { - if(user == null){ - return ResponseJson.builder().code(404).status(false).message("User cannot be null").build(); + public ResponseJson verifyMedic(Medic medic) { + ContactInfo contactInfo = medic.getContactInfo(); + Medic findMedic = mongoTemplate.findOne(new Query(Criteria.where("email").is(contactInfo.getEmail())), Medic.class); + if (findMedic == null) { + return ResponseJson.builder().code(404).status(false).message("Medic does not exist").build(); + } + if (findMedic.getGpg() == null) { + return ResponseJson.builder().code(404).status(false).message("Medic does not have a GPG key").build(); } try { - User userExists = mongoTemplate.findOne(new Query(Criteria.where("email").is(user.getEmail())), User.class); - if (userExists == null) { - return ResponseJson.builder().code(404).status(false).message("User not found").build(); - } - if (userExists.isMedic()) { - HashMap gpg = userExists.getGpg(); - return ResponseJson.builder().code(200).status(true).message("User is a medic").gpg(gpg).build(); - } else { - return ResponseJson.builder().code(404).status(false).message("User is not a medic").build(); - } + HashMap gpg = findMedic.getGpg(); + return ResponseJson.builder().code(200).status(true).message("Medic verified").gpg(gpg).build(); } catch (Exception e) { return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); } @@ -58,49 +52,70 @@ public ResponseJson loginUser(LoginData loginData) { return ResponseJson.builder().code(404).status(false).message("Email or password cannot be null").build(); } try { - User user = mongoTemplate.findOne(new Query(Criteria.where("email").is(loginData.getEmail())), User.class); + User user = mongoTemplate.findOne(new Query(Criteria.where("email").is(loginData.getEmail())), User.class); if (user == null) { - return ResponseJson.builder().code(404).status(false).message("User not found").build(); - } - if (BCrypt.checkpw(loginData.getPassword(), user.getPassword())) { - UsersLoginResponseDto responseDto = UsersLoginResponseDto.builder() - .id(user.getId()) - .email(user.getEmail()) - .username(user.getUsername()) - .isDoctor(user.isMedic()) - .fullName(user.getFullName()) - .build(); - String jsonStringTokenContent = objectMapper.writeValueAsString(responseDto); - String token = jwtUtil.getToken(jsonStringTokenContent); - System.out.println(jsonStringTokenContent); - return ResponseJson.builder() - .code(200) - .status(true) - .message("User logged in") - .token(token) - .build(); + Medic medic = mongoTemplate.findOne(new Query(Criteria.where("email").is(loginData.getEmail())), Medic.class); + if (medic == null) { + return ResponseJson.builder().code(404).status(false).message("User or medic not found").build(); + } else { + if (BCrypt.checkpw(loginData.getPassword(), medic.getPassword())) { + String jsonStringTokenContent = objectMapper.writeValueAsString(medic); + String token = jwtUtil.getToken(jsonStringTokenContent); + return ResponseJson.builder().code(200).status(true).message("Medic logged in").token(token).build(); + } else { + return ResponseJson.builder().code(404).status(false).message("Invalid password").build(); + } + } } else { - return ResponseJson.builder().code(404).status(false).message("Incorrect password").build(); + if (BCrypt.checkpw(loginData.getPassword(), user.getPassword())) { + String jsonStringTokenContent = objectMapper.writeValueAsString(user); + String token = jwtUtil.getToken(jsonStringTokenContent); + return ResponseJson.builder().code(200).status(true).message("User logged in").token(token).build(); + } else { + return ResponseJson.builder().code(404).status(false).message("Invalid password").build(); + } } - } catch (Exception e) { + } catch (Exception e) { return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); } } - public ResponseJson registerUser(User user){ - if(user == null){ + public ResponseJson registerUser(RegisterRequestDto registerRequestDto) { + if(registerRequestDto == null){ return ResponseJson.builder().code(404).status(false).message("User cannot be null").build(); } try { - User userExists = mongoTemplate.findOne(new Query(Criteria.where("email").is(user.getEmail())), User.class); - if (userExists != null) { - return ResponseJson.builder().code(404).status(false).message("User already exists").build(); - } - user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt())); - try { - mongoTemplate.save(user); - return ResponseJson.builder().code(200).status(true).message("User registered").build(); - } catch (Exception e) { - return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); + User user = registerRequestDto.getUser(); + if(user == null) { + Medic medic = registerRequestDto.getMedic(); + ContactInfo contactInfo = medic.getContactInfo(); + Medic findMedic = mongoTemplate.findOne(new Query(Criteria.where("email").is(contactInfo.getEmail())), Medic.class); + if (findMedic != null) { + return ResponseJson.builder().code(404).status(false).message("Medic already exists").build(); + } + medic.setPassword(BCrypt.hashpw(medic.getPassword(), BCrypt.gensalt())); + medic.setCreatedAt(new Date()); + medic.setUpdatedAt(new Date()); + medic.setGpg(gpgKeyGenerator.generateKey(contactInfo.getEmail(), medic.getPassword())); + try { + mongoTemplate.save(medic); + return ResponseJson.builder().code(200).status(true).message("Medic registered").build(); + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); + } + } else { + User findUser = mongoTemplate.findOne(new Query(Criteria.where("email").is(user.getEmail())), User.class); + if (findUser != null) { + return ResponseJson.builder().code(404).status(false).message("User already exists").build(); + } + user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt())); + user.setCreatedAt(new Date()); + user.setUpdatedAt(new Date()); + try { + mongoTemplate.save(user); + return ResponseJson.builder().code(200).status(true).message("User registered").build(); + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); + } } } catch (Exception e) { return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); From 694fb092e4d66d975b41c3ff7357c58b4b53d5b9 Mon Sep 17 00:00:00 2001 From: raresc4 Date: Sat, 9 Nov 2024 22:48:35 +0200 Subject: [PATCH 4/6] fixed controller --- .../main/java/com/stackbytes/controllers/UserController.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/users-service/src/main/java/com/stackbytes/controllers/UserController.java b/users-service/src/main/java/com/stackbytes/controllers/UserController.java index 2f6c0a0..f3b23e7 100644 --- a/users-service/src/main/java/com/stackbytes/controllers/UserController.java +++ b/users-service/src/main/java/com/stackbytes/controllers/UserController.java @@ -1,6 +1,7 @@ package com.stackbytes.controllers; import com.stackbytes.models.LoginData; +import com.stackbytes.models.RegisterRequestDto; import com.stackbytes.models.ResponseJson; import com.stackbytes.services.UserService; import org.springframework.beans.factory.annotation.Autowired; @@ -23,8 +24,8 @@ public ResponseJson loginUser(@RequestBody LoginData loginData) { } @CrossOrigin @PostMapping("/register") - public ResponseJson registerUser(@RequestBody User user) { - return userService.registerUser(user); + public ResponseJson registerUser(@RequestBody RegisterRequestDto registerRequestDto) { + return userService.registerUser(registerRequestDto); } @CrossOrigin @GetMapping("/test") From b293667a99147f9e80ade0fc14ec8708d0da5b9e Mon Sep 17 00:00:00 2001 From: raresc4 Date: Sun, 10 Nov 2024 02:12:42 +0200 Subject: [PATCH 5/6] almost fixed register, login not working properly --- users-service/pom.xml | 7 +- .../controllers/UserController.java | 2 +- .../java/com/stackbytes/models/LoginData.java | 1 + .../java/com/stackbytes/models/Medic.java | 3 +- .../com/stackbytes/models/ResponseJson.java | 3 +- .../stackbytes/services/GPGKeyGenerator.java | 109 ------------------ .../stackbytes/services/GPGKeyGenerator2.java | 65 +++++++++++ .../com/stackbytes/services/UserService.java | 92 +++++++++------ 8 files changed, 132 insertions(+), 150 deletions(-) delete mode 100644 users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java create mode 100644 users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator2.java diff --git a/users-service/pom.xml b/users-service/pom.xml index 5a2c625..1d6b128 100644 --- a/users-service/pom.xml +++ b/users-service/pom.xml @@ -67,16 +67,15 @@ 2.3.1 + org.bouncycastle - bcprov-jdk15on + bcpg-jdk15on 1.70 - - org.bouncycastle - bcpg-jdk15on + bcprov-jdk15on 1.70 diff --git a/users-service/src/main/java/com/stackbytes/controllers/UserController.java b/users-service/src/main/java/com/stackbytes/controllers/UserController.java index f3b23e7..4edef97 100644 --- a/users-service/src/main/java/com/stackbytes/controllers/UserController.java +++ b/users-service/src/main/java/com/stackbytes/controllers/UserController.java @@ -29,7 +29,7 @@ public ResponseJson registerUser(@RequestBody RegisterRequestDto registerRequest } @CrossOrigin @GetMapping("/test") - public String test() { + public String test() throws Exception{ return userService.test(); } } diff --git a/users-service/src/main/java/com/stackbytes/models/LoginData.java b/users-service/src/main/java/com/stackbytes/models/LoginData.java index dadafdf..2ce92e7 100644 --- a/users-service/src/main/java/com/stackbytes/models/LoginData.java +++ b/users-service/src/main/java/com/stackbytes/models/LoginData.java @@ -8,4 +8,5 @@ public class LoginData { private String email; private String password; + private boolean isMedic; } diff --git a/users-service/src/main/java/com/stackbytes/models/Medic.java b/users-service/src/main/java/com/stackbytes/models/Medic.java index 1e12c83..562197b 100644 --- a/users-service/src/main/java/com/stackbytes/models/Medic.java +++ b/users-service/src/main/java/com/stackbytes/models/Medic.java @@ -5,6 +5,7 @@ import lombok.Getter; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.util.Pair; import java.util.Date; import java.util.HashMap; @@ -22,7 +23,7 @@ public class Medic { private Date activeSince; private String speciality; private String grade; - private HashMap gpg; + private Pair gpg; private String workPlace; private double ratings; private String bio; diff --git a/users-service/src/main/java/com/stackbytes/models/ResponseJson.java b/users-service/src/main/java/com/stackbytes/models/ResponseJson.java index 665a3cd..f8a6b79 100644 --- a/users-service/src/main/java/com/stackbytes/models/ResponseJson.java +++ b/users-service/src/main/java/com/stackbytes/models/ResponseJson.java @@ -2,6 +2,7 @@ import lombok.Builder; import lombok.Getter; +import org.springframework.data.util.Pair; import java.util.HashMap; @@ -12,5 +13,5 @@ public class ResponseJson { private boolean status; private String message; private String token; - private HashMap gpg; + private Pair gpg; } diff --git a/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java b/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java deleted file mode 100644 index e517a5c..0000000 --- a/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.stackbytes.services; - -import jakarta.annotation.PostConstruct; -import org.bouncycastle.bcpg.HashAlgorithmTags; -import org.bouncycastle.bcpg.sig.KeyFlags; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openpgp.*; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; -import org.bouncycastle.openpgp.operator.PGPDigestCalculator; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; -import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; -import java.nio.charset.StandardCharsets; -import java.security.*; -import java.util.Base64; -import java.util.Date; -import java.util.HashMap; - -@Configuration -public class GPGKeyGenerator { - @Autowired - private GetProperties getProperties; - @PostConstruct - public void init() { - BouncyCastleSetup.setup(); - } - - private SecretKey generateAESKeyFromInput(String input) throws Exception { - // Convert the input string to a byte array (use it as salt) - byte[] salt = Base64.getDecoder().decode(input); - String secret = getProperties.getProperties("jwt.secret"); - // Define parameters for PBKDF2 - String password = secret; // Use a fixed password or other secret input - int iterationCount = 65536; // Number of PBKDF2 iterations - int keyLength = 256; // AES-256 - - // Derive the AES key using PBKDF2 - PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterationCount, keyLength); - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); - byte[] keyBytes = keyFactory.generateSecret(spec).getEncoded(); - - // Convert derived key bytes to AES SecretKey - return new SecretKeySpec(keyBytes, "AES"); - } - - public HashMap encryptPrivateKeyWithAES(String privateKey, PublicKey rsaPublicKey) throws Exception { - // Generate a random AES key - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); // AES-256 - SecretKey aesKey = generateAESKeyFromInput(getProperties.getProperties("aes_key")); - - // Encrypt the private key with AES - Cipher aesCipher = Cipher.getInstance("AES"); - aesCipher.init(Cipher.ENCRYPT_MODE, aesKey); - byte[] encryptedPrivateKey = aesCipher.doFinal(privateKey.getBytes(StandardCharsets.UTF_8)); - -// // Encrypt the AES key with RSA -// Cipher rsaCipher = Cipher.getInstance("RSA"); -// rsaCipher.init(Cipher.WRAP_MODE, rsaPublicKey); -// byte[] encryptedAESKey = rsaCipher.wrap(aesKey); - - // Encode both encrypted AES key and private key as Base64 strings - HashMap encryptedKeys = new HashMap<>(); - encryptedKeys.put("encryptedPrivateKey", Base64.getEncoder().encodeToString(encryptedPrivateKey)); - encryptedKeys.put("AESKey", Base64.getEncoder().encodeToString(aesKey.getEncoded())); - return encryptedKeys; - } - -// private String encryptBase64String(String base64String, PublicKey publicKey) throws Exception { -// byte[] dataToEncrypt = Base64.getDecoder().decode(base64String); -// Cipher cipher = Cipher.getInstance("RSA"); -// cipher.init(Cipher.ENCRYPT_MODE, publicKey); -// byte[] encryptedData = cipher.doFinal(dataToEncrypt); -// return Base64.getEncoder().encodeToString(encryptedData); -// } - public HashMap generateKey(String identity, String passphrase) { - try { - HashMap keyPair = new HashMap<>(); - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); - keyPairGenerator.initialize(2048, new SecureRandom()); - KeyPair keyPairRSA = keyPairGenerator.generateKeyPair(); - PGPKeyPair pgpKeyPair = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, keyPairRSA, new Date()); - PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); - PBESecretKeyEncryptor secretKeyEncryptor = new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc).setProvider("BC").build(passphrase.toCharArray()); - PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, pgpKeyPair, identity, sha1Calc, null, null, new JcaPGPContentSignerBuilder(pgpKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1), secretKeyEncryptor); - String initialPublicKey = keyRingGen.generatePublicKeyRing().getEncoded().toString(); - String publicKey = Base64.getEncoder().encodeToString(initialPublicKey.getBytes()); - String privateKey = Base64.getEncoder().encodeToString(keyRingGen.generateSecretKeyRing().getEncoded()); - HashMap encryptedPrivateKey = encryptPrivateKeyWithAES(privateKey, keyPairRSA.getPublic()); - keyPair.put("privateKey", encryptedPrivateKey.get("encryptedPrivateKey")); - keyPair.put("AESKey", encryptedPrivateKey.get("AESKey")); - keyPair.put("publicKey", publicKey); - return keyPair; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } -} diff --git a/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator2.java b/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator2.java new file mode 100644 index 0000000..a183d31 --- /dev/null +++ b/users-service/src/main/java/com/stackbytes/services/GPGKeyGenerator2.java @@ -0,0 +1,65 @@ +package com.stackbytes.services; + +import jakarta.annotation.PostConstruct; +import org.bouncycastle.openpgp.*; +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; +import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.PGPDigestCalculator; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; + +import java.io.ByteArrayOutputStream; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.util.Date; + +@Component +public class GPGKeyGenerator2 { + @Autowired + private GetProperties getProperties; + @PostConstruct + public void init() { + BouncyCastleSetup.setup(); + } + + public PGPKeyRingGenerator generateKey(String id) throws Exception{ + String passphrase = getProperties.getProperties("gpg.passphrase"); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + KeyPair rsaKeyPair = keyPairGenerator.generateKeyPair(); + PGPKeyPair pgpKeyPair = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, rsaKeyPair, new Date()); + PGPDigestCalculator sha256Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(PGPUtil.SHA1); + PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256, sha256Calc) + .setProvider("BC") + .build(passphrase.toCharArray()); + PGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(pgpKeyPair.getPublicKey().getAlgorithm(), PGPUtil.SHA1) + .setProvider("BC"); + return new PGPKeyRingGenerator( + PGPSignature.POSITIVE_CERTIFICATION, + pgpKeyPair, + id, + sha256Calc, + null, + null, + contentSignerBuilder, + keyEncryptor + ); + } + public byte[] getPublicKeyBytes(PGPKeyRingGenerator keyRingGenerator) throws Exception { + PGPPublicKeyRing publicKeyRing = keyRingGenerator.generatePublicKeyRing(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + publicKeyRing.encode(out); + return out.toByteArray(); + } + public byte[] getPrivateKeyBytes(PGPKeyRingGenerator keyRingGenerator) throws Exception { + PGPSecretKeyRing secretKeyRing = keyRingGenerator.generateSecretKeyRing(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + secretKeyRing.encode(out); + return out.toByteArray(); + } +} diff --git a/users-service/src/main/java/com/stackbytes/services/UserService.java b/users-service/src/main/java/com/stackbytes/services/UserService.java index 2191585..0a0cf09 100644 --- a/users-service/src/main/java/com/stackbytes/services/UserService.java +++ b/users-service/src/main/java/com/stackbytes/services/UserService.java @@ -1,15 +1,19 @@ package com.stackbytes.services; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ser.Serializers; import com.stackbytes.models.*; +import org.bouncycastle.openpgp.PGPKeyRingGenerator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; import org.mindrot.jbcrypt.BCrypt; +import java.util.Base64; import java.util.Date; import java.util.HashMap; @@ -17,7 +21,7 @@ public class UserService { private final MongoTemplate mongoTemplate; @Autowired - private GPGKeyGenerator gpgKeyGenerator; + private GPGKeyGenerator2 gpgKeyGenerator2; @Autowired private JwtUtil jwtUtil; @Autowired @@ -37,46 +41,60 @@ public ResponseJson verifyMedic(Medic medic) { return ResponseJson.builder().code(404).status(false).message("Medic does not have a GPG key").build(); } try { - HashMap gpg = findMedic.getGpg(); + Pair gpg = medic.getGpg(); return ResponseJson.builder().code(200).status(true).message("Medic verified").gpg(gpg).build(); } catch (Exception e) { return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); } } - public String test() { - HashMap response = gpgKeyGenerator.generateKey("test", "test"); - return "public key : " + response.get("publicKey") + "\nprivate key : " + response.get("privateKey") + "\nAESKey : " + response.get("AESKey"); + public String test() throws Exception{ + PGPKeyRingGenerator keyGenerator = gpgKeyGenerator2.generateKey("rares"); + byte[] publicKey = gpgKeyGenerator2.getPublicKeyBytes(keyGenerator); + byte[] privateKey = gpgKeyGenerator2.getPrivateKeyBytes(keyGenerator); + return "public key : " + Base64.getEncoder().encodeToString(publicKey) + "\nprivate key : " + Base64.getEncoder().encodeToString(privateKey); } public ResponseJson loginUser(LoginData loginData) { if (loginData.getEmail() == null || loginData.getPassword() == null) { return ResponseJson.builder().code(404).status(false).message("Email or password cannot be null").build(); } - try { - User user = mongoTemplate.findOne(new Query(Criteria.where("email").is(loginData.getEmail())), User.class); - if (user == null) { - Medic medic = mongoTemplate.findOne(new Query(Criteria.where("email").is(loginData.getEmail())), Medic.class); - if (medic == null) { - return ResponseJson.builder().code(404).status(false).message("User or medic not found").build(); - } else { - if (BCrypt.checkpw(loginData.getPassword(), medic.getPassword())) { - String jsonStringTokenContent = objectMapper.writeValueAsString(medic); - String token = jwtUtil.getToken(jsonStringTokenContent); - return ResponseJson.builder().code(200).status(true).message("Medic logged in").token(token).build(); - } else { - return ResponseJson.builder().code(404).status(false).message("Invalid password").build(); - } + if(loginData.isMedic()) { + Medic medic = mongoTemplate.findOne(new Query(Criteria.where("contactInfo.email").is(loginData.getEmail())), Medic.class); + if (medic == null) { + return ResponseJson.builder().code(404).status(false).message("Medic not found").build(); + } + if (BCrypt.checkpw(loginData.getPassword(), medic.getPassword())) { + String jsonStringTokenContent = null; + try { + jsonStringTokenContent = objectMapper.writeValueAsString(medic); + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message(e.getMessage()).build(); } + String token = jwtUtil.getToken(jsonStringTokenContent); + return ResponseJson.builder().code(200).status(true).message("Medic logged in").token(token).build(); } else { - if (BCrypt.checkpw(loginData.getPassword(), user.getPassword())) { - String jsonStringTokenContent = objectMapper.writeValueAsString(user); - String token = jwtUtil.getToken(jsonStringTokenContent); - return ResponseJson.builder().code(200).status(true).message("User logged in").token(token).build(); - } else { - return ResponseJson.builder().code(404).status(false).message("Invalid password").build(); + return ResponseJson.builder().code(404).status(false).message("Invalid password").build(); + } + } else { + try { + User user = mongoTemplate.findOne(new Query(Criteria.where("email").is(loginData.getEmail())), User.class); + if (user == null) { + return ResponseJson.builder().code(404).status(false).message("User not found").build(); + } + if (BCrypt.checkpw(loginData.getPassword(), user.getPassword())) { + String jsonStringTokenContent = null; + try { + jsonStringTokenContent = objectMapper.writeValueAsString(user); + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message(e.getMessage()).build(); } + String token = jwtUtil.getToken(jsonStringTokenContent); + return ResponseJson.builder().code(200).status(true).message("User logged in").token(token).build(); + } else { + return ResponseJson.builder().code(404).status(false).message("Invalid password").build(); + } + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message(e.getMessage()).build(); } - } catch (Exception e) { - return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); } } public ResponseJson registerUser(RegisterRequestDto registerRequestDto) { @@ -88,19 +106,25 @@ public ResponseJson registerUser(RegisterRequestDto registerRequestDto) { if(user == null) { Medic medic = registerRequestDto.getMedic(); ContactInfo contactInfo = medic.getContactInfo(); - Medic findMedic = mongoTemplate.findOne(new Query(Criteria.where("email").is(contactInfo.getEmail())), Medic.class); + Medic findMedic = mongoTemplate.findOne(new Query(Criteria.where("contactInfo.email").is(contactInfo.getEmail())), Medic.class); if (findMedic != null) { return ResponseJson.builder().code(404).status(false).message("Medic already exists").build(); } - medic.setPassword(BCrypt.hashpw(medic.getPassword(), BCrypt.gensalt())); - medic.setCreatedAt(new Date()); - medic.setUpdatedAt(new Date()); - medic.setGpg(gpgKeyGenerator.generateKey(contactInfo.getEmail(), medic.getPassword())); + medic.setPassword(BCrypt.hashpw(medic.getPassword(), BCrypt.gensalt())); + medic.setCreatedAt(new Date()); + medic.setUpdatedAt(new Date()); + PGPKeyRingGenerator keyGenerator = gpgKeyGenerator2.generateKey(contactInfo.getEmail()); + String publicKey = gpgKeyGenerator2.getPublicKeyBytes(keyGenerator).toString(); + String privateKey = gpgKeyGenerator2.getPrivateKeyBytes(keyGenerator).toString(); + String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getBytes()); + String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getBytes()); + Pair gpg = Pair.of(publicKeyString,privateKeyString); + medic.setGpg(gpg); try { - mongoTemplate.save(medic); + mongoTemplate.insert(medic); return ResponseJson.builder().code(200).status(true).message("Medic registered").build(); } catch (Exception e) { - return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); + return ResponseJson.builder().code(500).status(false).message(e.getMessage()).build(); } } else { User findUser = mongoTemplate.findOne(new Query(Criteria.where("email").is(user.getEmail())), User.class); From cf411f710761faa81e5263fa6a893f7a36bf213d Mon Sep 17 00:00:00 2001 From: raresc4 Date: Sun, 10 Nov 2024 10:28:02 +0200 Subject: [PATCH 6/6] fixed register and login --- .../controllers/UserController.java | 2 +- .../com/stackbytes/models/ContactInfo.java | 1 - .../java/com/stackbytes/models/LoginData.java | 2 + .../stackbytes/models/RegisterRequestDto.java | 6 ++- .../com/stackbytes/services/UserService.java | 49 +++++++++++-------- 5 files changed, 36 insertions(+), 24 deletions(-) diff --git a/users-service/src/main/java/com/stackbytes/controllers/UserController.java b/users-service/src/main/java/com/stackbytes/controllers/UserController.java index 4edef97..6a2df21 100644 --- a/users-service/src/main/java/com/stackbytes/controllers/UserController.java +++ b/users-service/src/main/java/com/stackbytes/controllers/UserController.java @@ -24,7 +24,7 @@ public ResponseJson loginUser(@RequestBody LoginData loginData) { } @CrossOrigin @PostMapping("/register") - public ResponseJson registerUser(@RequestBody RegisterRequestDto registerRequestDto) { + public ResponseJson registerUser(@RequestBody RegisterRequestDto registerRequestDto) throws Exception{ return userService.registerUser(registerRequestDto); } @CrossOrigin diff --git a/users-service/src/main/java/com/stackbytes/models/ContactInfo.java b/users-service/src/main/java/com/stackbytes/models/ContactInfo.java index b2aab0b..303cc62 100644 --- a/users-service/src/main/java/com/stackbytes/models/ContactInfo.java +++ b/users-service/src/main/java/com/stackbytes/models/ContactInfo.java @@ -10,5 +10,4 @@ public class ContactInfo { private String phone; private String email; - private String address; } diff --git a/users-service/src/main/java/com/stackbytes/models/LoginData.java b/users-service/src/main/java/com/stackbytes/models/LoginData.java index 2ce92e7..56e1bd8 100644 --- a/users-service/src/main/java/com/stackbytes/models/LoginData.java +++ b/users-service/src/main/java/com/stackbytes/models/LoginData.java @@ -1,10 +1,12 @@ package com.stackbytes.models; import lombok.Builder; +import lombok.Data; import lombok.Getter; @Builder @Getter +@Data public class LoginData { private String email; private String password; diff --git a/users-service/src/main/java/com/stackbytes/models/RegisterRequestDto.java b/users-service/src/main/java/com/stackbytes/models/RegisterRequestDto.java index 79f9358..5e42f67 100644 --- a/users-service/src/main/java/com/stackbytes/models/RegisterRequestDto.java +++ b/users-service/src/main/java/com/stackbytes/models/RegisterRequestDto.java @@ -5,9 +5,13 @@ import lombok.Getter; @Builder -@Data @Getter +@Data public class RegisterRequestDto { private User user; private Medic medic; + private boolean isMedic; + public boolean isMedic() { + return isMedic; + } } diff --git a/users-service/src/main/java/com/stackbytes/services/UserService.java b/users-service/src/main/java/com/stackbytes/services/UserService.java index 0a0cf09..6911b40 100644 --- a/users-service/src/main/java/com/stackbytes/services/UserService.java +++ b/users-service/src/main/java/com/stackbytes/services/UserService.java @@ -57,7 +57,8 @@ public ResponseJson loginUser(LoginData loginData) { if (loginData.getEmail() == null || loginData.getPassword() == null) { return ResponseJson.builder().code(404).status(false).message("Email or password cannot be null").build(); } - if(loginData.isMedic()) { + if(loginData.isMedic() == true) { + System.out.println("medic"); Medic medic = mongoTemplate.findOne(new Query(Criteria.where("contactInfo.email").is(loginData.getEmail())), Medic.class); if (medic == null) { return ResponseJson.builder().code(404).status(false).message("Medic not found").build(); @@ -76,7 +77,9 @@ public ResponseJson loginUser(LoginData loginData) { } } else { try { + System.out.println("user"); User user = mongoTemplate.findOne(new Query(Criteria.where("email").is(loginData.getEmail())), User.class); + System.out.println("here1"); if (user == null) { return ResponseJson.builder().code(404).status(false).message("User not found").build(); } @@ -97,36 +100,40 @@ public ResponseJson loginUser(LoginData loginData) { } } } - public ResponseJson registerUser(RegisterRequestDto registerRequestDto) { - if(registerRequestDto == null){ + public ResponseJson registerUser(RegisterRequestDto registerRequestDto) throws Exception{ + if (registerRequestDto == null) { return ResponseJson.builder().code(404).status(false).message("User cannot be null").build(); } - try { - User user = registerRequestDto.getUser(); - if(user == null) { + if (registerRequestDto.isMedic()) { + try { Medic medic = registerRequestDto.getMedic(); ContactInfo contactInfo = medic.getContactInfo(); Medic findMedic = mongoTemplate.findOne(new Query(Criteria.where("contactInfo.email").is(contactInfo.getEmail())), Medic.class); if (findMedic != null) { return ResponseJson.builder().code(404).status(false).message("Medic already exists").build(); } - medic.setPassword(BCrypt.hashpw(medic.getPassword(), BCrypt.gensalt())); - medic.setCreatedAt(new Date()); - medic.setUpdatedAt(new Date()); - PGPKeyRingGenerator keyGenerator = gpgKeyGenerator2.generateKey(contactInfo.getEmail()); - String publicKey = gpgKeyGenerator2.getPublicKeyBytes(keyGenerator).toString(); - String privateKey = gpgKeyGenerator2.getPrivateKeyBytes(keyGenerator).toString(); - String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getBytes()); - String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getBytes()); - Pair gpg = Pair.of(publicKeyString,privateKeyString); - medic.setGpg(gpg); + medic.setPassword(BCrypt.hashpw(medic.getPassword(), BCrypt.gensalt())); + medic.setCreatedAt(new Date()); + medic.setUpdatedAt(new Date()); + PGPKeyRingGenerator keyGenerator = gpgKeyGenerator2.generateKey(contactInfo.getEmail()); + String publicKey = gpgKeyGenerator2.getPublicKeyBytes(keyGenerator).toString(); + String privateKey = gpgKeyGenerator2.getPrivateKeyBytes(keyGenerator).toString(); + String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getBytes()); + String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getBytes()); + Pair gpg = Pair.of(publicKeyString, privateKeyString); + medic.setGpg(gpg); try { mongoTemplate.insert(medic); return ResponseJson.builder().code(200).status(true).message("Medic registered").build(); } catch (Exception e) { return ResponseJson.builder().code(500).status(false).message(e.getMessage()).build(); } - } else { + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message(e.getMessage()).build(); + } + } else { + try { + User user = registerRequestDto.getUser(); User findUser = mongoTemplate.findOne(new Query(Criteria.where("email").is(user.getEmail())), User.class); if (findUser != null) { return ResponseJson.builder().code(404).status(false).message("User already exists").build(); @@ -135,14 +142,14 @@ public ResponseJson registerUser(RegisterRequestDto registerRequestDto) { user.setCreatedAt(new Date()); user.setUpdatedAt(new Date()); try { - mongoTemplate.save(user); + mongoTemplate.insert(user); return ResponseJson.builder().code(200).status(true).message("User registered").build(); } catch (Exception e) { - return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); + return ResponseJson.builder().code(500).status(false).message(e.getMessage()).build(); } + } catch (Exception e) { + return ResponseJson.builder().code(500).status(false).message(e.getMessage()).build(); } - } catch (Exception e) { - return ResponseJson.builder().code(500).status(false).message("Internal server error").build(); } } }