diff --git a/certify-core/pom.xml b/certify-core/pom.xml
index 7dcf89fb..245407df 100644
--- a/certify-core/pom.xml
+++ b/certify-core/pom.xml
@@ -82,6 +82,11 @@
org.springframework.boot
spring-boot-starter-data-jpa
+
+ org.springframework.boot
+ spring-boot-test
+ test
+
diff --git a/certify-core/src/main/java/io/mosip/certify/core/constants/SignatureAlg.java b/certify-core/src/main/java/io/mosip/certify/core/constants/SignatureAlg.java
index af68794f..b5903d77 100644
--- a/certify-core/src/main/java/io/mosip/certify/core/constants/SignatureAlg.java
+++ b/certify-core/src/main/java/io/mosip/certify/core/constants/SignatureAlg.java
@@ -1,8 +1,15 @@
package io.mosip.certify.core.constants;
+/**
+ * SignatureAlg is the constants file of supported VC sign algorithms.
+ * TODO(later): convert this into a structure such that it enables
+ * consumers to choose VC sign algos with
+ */
public class SignatureAlg {
// LinkedDataSignature Algorithms
- public static final String RSA_SIGNATURE_2018 = "RsaSignature2018";
+ public static final String RSA_SIGNATURE_SUITE = "RsaSignature2018";
- // RS256, PS256, ES256
+ public static final String ED25519_SIGNATURE_SUITE = "Ed25519Signature2018";
+
+ // RS256, PS256, ES256 --> JWSAlgorithm.RS256.getName();
}
diff --git a/certify-core/src/main/java/io/mosip/certify/core/entity/TemplateData.java b/certify-core/src/main/java/io/mosip/certify/core/entity/TemplateData.java
index e12ee4fa..21ce3891 100644
--- a/certify-core/src/main/java/io/mosip/certify/core/entity/TemplateData.java
+++ b/certify-core/src/main/java/io/mosip/certify/core/entity/TemplateData.java
@@ -3,25 +3,27 @@
import jakarta.persistence.Entity;
import jakarta.persistence.*;
-import lombok.AllArgsConstructor;
-import lombok.Data;
+import lombok.*;
import jakarta.validation.constraints.NotBlank;
-import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Objects;
-@Data
@Entity
@NoArgsConstructor
-@AllArgsConstructor
@IdClass(TemplateId.class)
public class TemplateData {
@NotBlank(message = "Template is mandatory")
+ @Getter
+ @Setter
private String template;
@Id
+ @Getter
+ @Setter
private String context;
@Id
+ @Getter
+ @Setter
private String credentialType;
}
diff --git a/certify-core/src/main/java/io/mosip/certify/core/entity/TemplateId.java b/certify-core/src/main/java/io/mosip/certify/core/entity/TemplateId.java
index b726c955..ef472d04 100644
--- a/certify-core/src/main/java/io/mosip/certify/core/entity/TemplateId.java
+++ b/certify-core/src/main/java/io/mosip/certify/core/entity/TemplateId.java
@@ -1,16 +1,18 @@
package io.mosip.certify.core.entity;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
+import lombok.*;
+
import java.io.Serializable;
import java.util.Objects;
-@Data
-@AllArgsConstructor
@NoArgsConstructor
+@AllArgsConstructor
public class TemplateId implements Serializable {
+ @Getter
+ @Setter
private String context;
+ @Getter
+ @Setter
private String credentialType;
@Override
diff --git a/certify-core/src/test/java/io/mosip/certify/core/templating/VelocityTemplatingEngineImplTest.java b/certify-core/src/test/java/io/mosip/certify/core/templating/VelocityTemplatingEngineImplTest.java
index 6c056c21..902c178d 100644
--- a/certify-core/src/test/java/io/mosip/certify/core/templating/VelocityTemplatingEngineImplTest.java
+++ b/certify-core/src/test/java/io/mosip/certify/core/templating/VelocityTemplatingEngineImplTest.java
@@ -1,22 +1,35 @@
package io.mosip.certify.core.templating;
+import io.mosip.certify.core.repository.TemplateRepository;
import junit.framework.TestCase;
+import lombok.SneakyThrows;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+import org.json.JSONArray;
import org.junit.Before;
import org.junit.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+@Component
public class VelocityTemplatingEngineImplTest extends TestCase {
private VelocityEngine engine;
private final Map templateCache = new ConcurrentHashMap<>();
+ @MockBean
+ private TemplateRepository templateRepository;
@Before
public void setUp() throws Exception {
@@ -24,19 +37,52 @@ public void setUp() throws Exception {
engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
engine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.NullLogChute");
+ engine.setProperty(RuntimeConstants.INPUT_ENCODING, "UTF-8");
+ engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
engine.init();
}
+ @SneakyThrows
@Test
public void testTemplating() {
// 1. setup template
- Template t = engine.getTemplate("SchoolTemplate.vm");
+ Template t = engine.getTemplate("MockCredential.vm");
assert t != null;
- Map templateInput = new HashMap<>();
VelocityContext c = new VelocityContext();
StringWriter writer = new StringWriter();
engine.evaluate(c, writer, "SchoolTemplateTest", t.toString());
String out = writer.toString();
-
+ Map res = new RestTemplate().getForObject(
+ "https://api.dev1.mosip.net/v1/mock-identity-system/identity/34455445765",
+ HashMap.class);
+ res = (Map) res.get("response");
+ Map ret = new HashMap<>();
+ ret.put("vcVer", "VC-V1");
+ ret.put("name", res.get("name"));
+ ret.put("fullName", res.get("fullName"));
+ ret.put("gender", res.get("gender"));
+ ret.put("dateOfBirth", res.get("dateOfBirth"));
+ ret.put("email", res.get("email"));
+ ret.put("UIN", "34455445765");
+ ret.put("phone", res.get("phone"));
+ ret.put("addressLine1", res.get("streetAddress"));
+ ret.put("province", res.get("locality"));
+ ret.put("region", res.get("region"));
+ ret.put("postalCode", res.get("postalCode"));
+ ret.put("face", res.get("encodedPhoto"));
+ Map finalTemplate = new HashMap<>();
+ for (String key : ret.keySet()) {
+ Object value = ret.get(key);
+ if (value instanceof List) {
+ finalTemplate.put(key, new JSONArray((List) value));
+ } else if (value instanceof JSONArray) {
+ finalTemplate.put(key, new JSONArray(value));
+ } else {
+ finalTemplate.put(key, value);
+ }
+ }
+ VelocityContext context = new VelocityContext(finalTemplate);
+ InputStream is = new ByteArrayInputStream(t.toString().getBytes(StandardCharsets.UTF_8));
+ t.merge(context, writer);
}
}
\ No newline at end of file
diff --git a/certify-core/src/test/resources/MockCredential.vm b/certify-core/src/test/resources/MockCredential.vm
new file mode 100644
index 00000000..3a5771c7
--- /dev/null
+++ b/certify-core/src/test/resources/MockCredential.vm
@@ -0,0 +1,23 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/credentials/v2"],
+ "issuer": "${issuer}",
+ "type": ["VerifiableCredential", "MockVerifiableCredential"],
+ "validFrom": "${validFrom}",
+ "validUntil": "${validUntil}",
+ "credentialSubject": {
+ "gender": ${gender},
+ "postalCode": ${postalCode},
+ "fullName": ${fullName},
+ "dateOfBirth": "${dateOfBirth}",
+ "province": ${province},
+ "phone": "${phone}",
+ "addressLine1": ${addressLine1},
+ "region": ${region},
+ "vcVer": "${vcVer}",
+ "UIN": ${UIN},
+ "email": "${email}",
+ "id": "${id}",
+ "face": "${face}"
+ }
+}
diff --git a/certify-service/src/main/java/io/mosip/certify/CertifyServiceApplication.java b/certify-service/src/main/java/io/mosip/certify/CertifyServiceApplication.java
index 2683923d..c6d89a31 100644
--- a/certify-service/src/main/java/io/mosip/certify/CertifyServiceApplication.java
+++ b/certify-service/src/main/java/io/mosip/certify/CertifyServiceApplication.java
@@ -14,7 +14,6 @@
@EnableAsync
@EnableCaching
-@EnableJpaRepositories
@SpringBootApplication(scanBasePackages = "io.mosip.certify,"+
"io.mosip.certify.core.*," +
"io.mosip.kernel.crypto," +
diff --git a/certify-service/src/main/java/io/mosip/certify/config/AppConfig.java b/certify-service/src/main/java/io/mosip/certify/config/AppConfig.java
index 80ce6027..279ea110 100644
--- a/certify-service/src/main/java/io/mosip/certify/config/AppConfig.java
+++ b/certify-service/src/main/java/io/mosip/certify/config/AppConfig.java
@@ -30,7 +30,7 @@
import org.springframework.web.client.RestTemplate;
@Configuration
-@EnableJpaRepositories(basePackages = {"io.mosip.kernel.keymanagerservice.repository"})
+@EnableJpaRepositories(basePackages = {"io.mosip.kernel.keymanagerservice.repository", "io.mosip.certify.core.repository"})
@EntityScan(basePackages = {"io.mosip.kernel.keymanagerservice.entity, io.mosip.certify.core.entity"})
@Slf4j
public class AppConfig implements ApplicationRunner {
diff --git a/certify-service/src/main/java/io/mosip/certify/services/KeymanagerLibSigner.java b/certify-service/src/main/java/io/mosip/certify/services/KeymanagerLibSigner.java
index b14cc878..8e9bbc64 100644
--- a/certify-service/src/main/java/io/mosip/certify/services/KeymanagerLibSigner.java
+++ b/certify-service/src/main/java/io/mosip/certify/services/KeymanagerLibSigner.java
@@ -33,15 +33,16 @@ public class KeymanagerLibSigner implements VCSigner {
@Override
public VCResult perform(String templatedVC, Map keyMgrInput) {
// TODO: Can the below lines be done at Templating side itself? Ask Hitesh.
- VCResult VC = null;
+ VCResult VC = new VCResult<>();
JsonLDObject j = JsonLDObject.fromJson(templatedVC);
j.setDocumentLoader(null);
+ // NOTE: other aspects can be configured via keyMgrInput map
Date validFrom = Date
.from(LocalDateTime
.parse((String) j.getJsonObject().get(VCDM2Constants.VALID_FROM),
DateTimeFormatter.ofPattern(Constants.UTC_DATETIME_PATTERN))
.atZone(ZoneId.systemDefault()).toInstant());
- LdProof vcLdProof = LdProof.builder().defaultContexts(false).defaultTypes(false).type(SignatureAlg.RSA_SIGNATURE_2018)
+ LdProof vcLdProof = LdProof.builder().defaultContexts(false).defaultTypes(false).type(SignatureAlg.RSA_SIGNATURE_SUITE)
.created(validFrom).proofPurpose(VCDM2Constants.ASSERTION_METHOD)
.verificationMethod(URI.create("https://vharsh.github.io/DID/mock-public-key.json"))
// ^^ Why is this pointing to JWKS URL of eSignet??
diff --git a/certify-service/src/main/java/io/mosip/certify/services/templating/VelocityTemplatingEngineImpl.java b/certify-service/src/main/java/io/mosip/certify/services/templating/VelocityTemplatingEngineImpl.java
index 3ff025a5..b4714322 100644
--- a/certify-service/src/main/java/io/mosip/certify/services/templating/VelocityTemplatingEngineImpl.java
+++ b/certify-service/src/main/java/io/mosip/certify/services/templating/VelocityTemplatingEngineImpl.java
@@ -1,16 +1,23 @@
package io.mosip.certify.services.templating;
import java.io.*;
-import java.nio.charset.StandardCharsets;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.*;
-
import io.mosip.certify.api.spi.VCFormatter;
+import io.mosip.certify.core.constants.Constants;
+import io.mosip.certify.core.constants.VCDM2Constants;
import io.mosip.certify.core.repository.TemplateRepository;
import jakarta.annotation.PostConstruct;
+import lombok.SneakyThrows;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.tools.generic.DateTool;
+import org.json.JSONArray;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
@@ -20,12 +27,8 @@ public class VelocityTemplatingEngineImpl implements VCFormatter {
Map templateCache;
@Autowired
TemplateRepository templateRepository;
- // DATA to be fetched from DB
-
- @Autowired
- public void setTemplateRepository(TemplateRepository templateRepository) {
- this.templateRepository = templateRepository;
- }
+ @Value("${mosip.certify.vcformat.vc.expiry:true}")
+ boolean shouldHaveDates;
@PostConstruct
public void initialize() {
@@ -60,9 +63,29 @@ public String format(Map templateInput, Map defa
String templateName = defaultSettings.get("templateName").toString();
String t = templateCache.get(templateName);
StringWriter writer = new StringWriter();
- VelocityContext context = new VelocityContext(templateInput);
- // TODO: Check config for templateName.* fields and apply those configs as well, e.g. auto-fill validFrom & validUntil
- InputStream is = new ByteArrayInputStream(t.toString().getBytes(StandardCharsets.UTF_8));
+ // 1. Prepare map
+ Map finalTemplate = new HashMap<>();
+ for (String key : templateInput.keySet()) {
+ Object value = templateInput.get(key);
+ if (value instanceof List) {
+ // TODO(problem area): handle field values with unescaped JSON
+ // reserved literals such as " or ,
+ // (Q) Should Object always be a JSONObject?
+ finalTemplate.put(key, new JSONArray((List