// Path: src/main/java/com/membaza/api/users/persistence/User.java
// @Data
// @Document(collection = "users")
// public final class User {
// 
//     @Id
//     private String id;
// 
//     private @NotNull String firstname;
//     private @NotNull String lastname;
// 
//     @Indexed(unique=true)
//     private @NotNull String email;
//     private @NotNull String password;
//     private @NotNull Set<Role> roles;
//     private @NotNull Set<String> privileges;
//     private @NotNull Date dateRegistered;
//     private boolean confirmed;
//     private boolean enabled;
// 
//     @Indexed(unique=true)
//     private String userCreationCode;
//     private Set<EmailChange> emailChanges;
//     private Set<PasswordChange> passwordChanges;
//     private Set<UserDeletion> userDeletions;
// 
//     @JsonIgnore
//     public String getPassword(){
//         return password;
//     }
// 
//     @JsonIgnore
//     public String getUserCreationCode(){
//         return userCreationCode;
//     }
// }
// 
// Path: src/main/java/com/membaza/api/users/security/JwtToken.java
// public final class JwtToken {
// 
//     @Getter
//     private final String token;
// 
//     public JwtToken(String json) {
//         this.token = requireNonNull(json);
//     }
// }
// 
// Path: src/main/java/com/membaza/api/users/util/EncryptionUtil.java
// public final class EncryptionUtil {
// 
//     public static PublicKey getPublicKey(String filename) {
//         try {
//             final byte[] keyBytes = Files.readAllBytes(Paths.get(filename));
//             final X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
//             return factory().generatePublic(spec);
//         } catch (IOException ex) {
//             throw new RuntimeException(
//                 "Error loading public key '" + filename + "'.", ex
//             );
//         } catch (final InvalidKeySpecException ex) {
//             throw new RuntimeException(
//                 "Error reading public key '" + filename + "'.", ex
//             );
//         }
//     }
// 
//     public static PrivateKey getPrivateKey(String filename) {
//         try {
//             final byte[] keyBytes = Files.readAllBytes(Paths.get(filename));
//             final PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
//             return factory().generatePrivate(spec);
//         } catch (IOException ex) {
//             throw new RuntimeException(
//                 "Error loading private key '" + filename + "'.", ex
//             );
//         } catch (final InvalidKeySpecException ex) {
//             throw new RuntimeException(
//                 "Error reading private key '" + filename + "'.", ex
//             );
//         }
//     }
// 
//     private static KeyFactory factory() {
//         try {
//             return KeyFactory.getInstance("RSA");
//         } catch (final NoSuchAlgorithmException ex) {
//             throw new RuntimeException(
//                 "Could not find the RSA algorithm.", ex
//             );
//         }
//     }
// 
//     private EncryptionUtil() {}
// }


import com.membaza.api.users.persistence.User;
import com.membaza.api.users.security.JwtToken;
import com.membaza.api.users.util.EncryptionUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;
                .distinct()
                .collect(joining(",")),
            Long.parseLong(env.getProperty("service.jwt.expiration"))
        );
    }

    @Override
    public Claims validate(JwtToken token) {
        final Key signingKey = EncryptionUtil.getPublicKey(
            env.getProperty("service.jwt.public"));

        return Jwts.parser()
            .setSigningKey(signingKey)
            .parseClaimsJws(token.getToken())
            .getBody();
    }

    private JwtToken createJWT(String id,
                               String issuer,
                               String subject,
                               String privileges,
                               long ttlMillis) {

        // The JWT signature algorithm we will be using to sign the token
        final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256;

        final long nowMillis = System.currentTimeMillis();
        final Date now = new Date(nowMillis);

        // We will sign our JWT with our ApiKey secret
// Path: src/main/java/com/membaza/api/users/persistence/User.java
// @Data
// @Document(collection = "users")
// public final class User {
// 
//     @Id
//     private String id;
// 
//     private @NotNull String firstname;
//     private @NotNull String lastname;
// 
//     @Indexed(unique=true)
//     private @NotNull String email;
//     private @NotNull String password;
//     private @NotNull Set<Role> roles;
//     private @NotNull Set<String> privileges;
//     private @NotNull Date dateRegistered;
//     private boolean confirmed;
//     private boolean enabled;
// 
//     @Indexed(unique=true)
//     private String userCreationCode;
//     private Set<EmailChange> emailChanges;
//     private Set<PasswordChange> passwordChanges;
//     private Set<UserDeletion> userDeletions;
// 
//     @JsonIgnore
//     public String getPassword(){
//         return password;
//     }
// 
//     @JsonIgnore
//     public String getUserCreationCode(){
//         return userCreationCode;
//     }
// }
// 
// Path: src/main/java/com/membaza/api/users/security/JwtToken.java
// public final class JwtToken {
// 
//     @Getter
//     private final String token;
// 
//     public JwtToken(String json) {
//         this.token = requireNonNull(json);
//     }
// }
// 
// Path: src/main/java/com/membaza/api/users/util/EncryptionUtil.java
// public final class EncryptionUtil {
// 
//     public static PublicKey getPublicKey(String filename) {
//         try {
//             final byte[] keyBytes = Files.readAllBytes(Paths.get(filename));
//             final X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
//             return factory().generatePublic(spec);
//         } catch (IOException ex) {
//             throw new RuntimeException(
//                 "Error loading public key '" + filename + "'.", ex
//             );
//         } catch (final InvalidKeySpecException ex) {
//             throw new RuntimeException(
//                 "Error reading public key '" + filename + "'.", ex
//             );
//         }
//     }
// 
//     public static PrivateKey getPrivateKey(String filename) {
//         try {
//             final byte[] keyBytes = Files.readAllBytes(Paths.get(filename));
//             final PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
//             return factory().generatePrivate(spec);
//         } catch (IOException ex) {
//             throw new RuntimeException(
//                 "Error loading private key '" + filename + "'.", ex
//             );
//         } catch (final InvalidKeySpecException ex) {
//             throw new RuntimeException(
//                 "Error reading private key '" + filename + "'.", ex
//             );
//         }
//     }
// 
//     private static KeyFactory factory() {
//         try {
//             return KeyFactory.getInstance("RSA");
//         } catch (final NoSuchAlgorithmException ex) {
//             throw new RuntimeException(
//                 "Could not find the RSA algorithm.", ex
//             );
//         }
//     }
// 
//     private EncryptionUtil() {}
// }


// Path: src/main/java/com/membaza/api/users/service/jwt/JwtServiceImpl.java
import com.membaza.api.users.persistence.User;
import com.membaza.api.users.security.JwtToken;
import com.membaza.api.users.util.EncryptionUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;

                .distinct()
                .collect(joining(",")),
            Long.parseLong(env.getProperty("service.jwt.expiration"))
        );
    }

    @Override
    public Claims validate(JwtToken token) {
        final Key signingKey = EncryptionUtil.getPublicKey(
            env.getProperty("service.jwt.public"));

        return Jwts.parser()
            .setSigningKey(signingKey)
            .parseClaimsJws(token.getToken())
            .getBody();
    }

    private JwtToken createJWT(String id,
                               String issuer,
                               String subject,
                               String privileges,
                               long ttlMillis) {

        // The JWT signature algorithm we will be using to sign the token
        final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256;

        final long nowMillis = System.currentTimeMillis();
        final Date now = new Date(nowMillis);

        // We will sign our JWT with our ApiKey secret
        final Key signingKey = EncryptionUtil.getPrivateKey(