From 71515881b65d6b223aad06fd45ac4702f756114c Mon Sep 17 00:00:00 2001 From: Harsh Vardhan Date: Fri, 8 Nov 2024 18:33:45 +0530 Subject: [PATCH] [INJICERT-434] compute svg template multibase&sha256 per spec (#125) * [INJICERT-434] compute svg template multibase&sha256 per spec ref: https://w3c-ccg.github.io/vc-render-method/#svgrenderingtemplate Signed-off-by: Harsh Vardhan * [INJICERT-434] only fetch SVG template if VC 2.0 is requested Signed-off-by: Harsh Vardhan --------- Signed-off-by: Harsh Vardhan --- .../core/constants/VCDM1Constants.java | 1 + .../core/constants/VCDM2Constants.java | 1 + certify-service/pom.xml | 11 +++++++ .../services/CertifyIssuanceServiceImpl.java | 13 +++++--- .../certify/services/SVGRenderUtils.java | 31 +++++++++++++++++++ .../VelocityTemplatingConstants.java | 7 +++++ .../VelocityTemplatingEngineImpl.java | 22 +++++++++++-- .../certify/services/SVGRenderUtilsTest.java | 19 ++++++++++++ 8 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 certify-service/src/main/java/io/mosip/certify/services/SVGRenderUtils.java create mode 100644 certify-service/src/main/java/io/mosip/certify/services/templating/VelocityTemplatingConstants.java create mode 100644 certify-service/src/test/java/io/mosip/certify/services/SVGRenderUtilsTest.java diff --git a/certify-core/src/main/java/io/mosip/certify/core/constants/VCDM1Constants.java b/certify-core/src/main/java/io/mosip/certify/core/constants/VCDM1Constants.java index 197423b3..8e4a6eed 100644 --- a/certify-core/src/main/java/io/mosip/certify/core/constants/VCDM1Constants.java +++ b/certify-core/src/main/java/io/mosip/certify/core/constants/VCDM1Constants.java @@ -1,6 +1,7 @@ package io.mosip.certify.core.constants; public class VCDM1Constants { + public static final String URL = "https://www.w3.org/2018/credentials/v1"; public static final String ISSUANCE_DATE = "issuanceDate"; public static final String EXPIRATION_DATE = "expirationDate"; } diff --git a/certify-core/src/main/java/io/mosip/certify/core/constants/VCDM2Constants.java b/certify-core/src/main/java/io/mosip/certify/core/constants/VCDM2Constants.java index b3c77286..a0684e76 100644 --- a/certify-core/src/main/java/io/mosip/certify/core/constants/VCDM2Constants.java +++ b/certify-core/src/main/java/io/mosip/certify/core/constants/VCDM2Constants.java @@ -6,6 +6,7 @@ * ref: */ public class VCDM2Constants { + public static final String URL = "https://www.w3.org/ns/credentials/v2"; public static final String VALID_UNITL = "validUntil"; public static final String VALID_FROM = "validFrom"; } diff --git a/certify-service/pom.xml b/certify-service/pom.xml index 0fd3af4f..45fc947f 100644 --- a/certify-service/pom.xml +++ b/certify-service/pom.xml @@ -17,6 +17,12 @@ 0.10.0-SNAPSHOT certify-service certify vci service + + + jitpack.io + https://jitpack.io + + @@ -79,6 +85,11 @@ tink 1.13.0 + + com.github.multiformats + java-multibase + v1.1.1 + diff --git a/certify-service/src/main/java/io/mosip/certify/services/CertifyIssuanceServiceImpl.java b/certify-service/src/main/java/io/mosip/certify/services/CertifyIssuanceServiceImpl.java index 49d9fd50..d28ce076 100644 --- a/certify-service/src/main/java/io/mosip/certify/services/CertifyIssuanceServiceImpl.java +++ b/certify-service/src/main/java/io/mosip/certify/services/CertifyIssuanceServiceImpl.java @@ -5,8 +5,6 @@ */ package io.mosip.certify.services; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jose.JWSAlgorithm; import foundation.identity.jsonld.JsonLDObject; import io.mosip.certify.api.dto.VCRequestDto; @@ -34,6 +32,7 @@ import io.mosip.certify.exception.InvalidNonceException; import io.mosip.certify.proof.ProofValidator; import io.mosip.certify.proof.ProofValidatorFactory; +import io.mosip.certify.services.templating.VelocityTemplatingConstants; import io.mosip.certify.utils.CredentialUtils; import lombok.extern.slf4j.Slf4j; import org.json.JSONObject; @@ -88,6 +87,9 @@ public class CertifyIssuanceServiceImpl implements VCIssuanceService { @Value("${mosip.certify.issuer.vc-sign-algo:Ed25519Signature2018}") private String VCSignAlgo; + @Value("${mosip.certify.issuer.svg.template.id}") + private String svg; + @Autowired private AuditPlugin auditWrapper; @@ -158,8 +160,11 @@ private VCResult getVerifiableCredential(CredentialRequest credentialRequest, // TODO(multitenancy): later decide which plugin out of n plugins is the correct one JSONObject jsonObject = dataModelService.fetchData(parsedAccessToken.getClaims()); Map templateParams = new HashMap<>(); - templateParams.put("templateName", CredentialUtils.getTemplateName(vcRequestDto)); - templateParams.put("issuerURI", issuerURI); + templateParams.put(VelocityTemplatingConstants.TEMPLATE_NAME, CredentialUtils.getTemplateName(vcRequestDto)); + templateParams.put(VelocityTemplatingConstants.ISSUER_URI, issuerURI); + if (svg != null) { + templateParams.put(VelocityTemplatingConstants.SVG_TEMPLATE, svg); + } String templatedVC = vcFormatter.format(jsonObject, templateParams); Map vcSignerParams = new HashMap<>(); // TODO: Collate this into simpler APIs where just key-type is specified diff --git a/certify-service/src/main/java/io/mosip/certify/services/SVGRenderUtils.java b/certify-service/src/main/java/io/mosip/certify/services/SVGRenderUtils.java new file mode 100644 index 00000000..205dbf13 --- /dev/null +++ b/certify-service/src/main/java/io/mosip/certify/services/SVGRenderUtils.java @@ -0,0 +1,31 @@ +package io.mosip.certify.services; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import io.ipfs.multibase.Multibase; + +public class SVGRenderUtils { + /** + * Generate SVG digest for @param svg image as per spec. + * ref: https://w3c-ccg.github.io/vc-render-method/#svgrenderingtemplate + * + * @param svg + * @return + */ + public static String getDigestMultibase(String svg) { + /* + digestMultibase: An optional multibase-encoded multihash of the SVG image. + The multibase value MUST be z and the multihash value MUST + be SHA-2 with 256-bits of output (0x12). + */ + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] sha256 = digest.digest(svg.getBytes(StandardCharsets.UTF_8)); + return Multibase.encode(Multibase.Base.Base58BTC, sha256); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } +} diff --git a/certify-service/src/main/java/io/mosip/certify/services/templating/VelocityTemplatingConstants.java b/certify-service/src/main/java/io/mosip/certify/services/templating/VelocityTemplatingConstants.java new file mode 100644 index 00000000..3c33ce94 --- /dev/null +++ b/certify-service/src/main/java/io/mosip/certify/services/templating/VelocityTemplatingConstants.java @@ -0,0 +1,7 @@ +package io.mosip.certify.services.templating; + +public class VelocityTemplatingConstants { + public static final String TEMPLATE_NAME = "templateName"; + public static final String ISSUER_URI = "issuerURI"; + public static final String SVG_TEMPLATE = "svgTemplate"; +} 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 4966b5b9..a82aebcd 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 @@ -14,9 +14,13 @@ 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.exception.TemplateException; import io.mosip.certify.core.repository.TemplateRepository; +import io.mosip.certify.core.spi.SvgTemplateService; +import io.mosip.certify.services.SVGRenderUtils; import jakarta.annotation.PostConstruct; import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.runtime.RuntimeConstants; @@ -28,6 +32,9 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import static io.mosip.certify.services.templating.VelocityTemplatingConstants.*; + +@Slf4j @Service public class VelocityTemplatingEngineImpl implements VCFormatter { VelocityEngine engine; @@ -35,6 +42,8 @@ public class VelocityTemplatingEngineImpl implements VCFormatter { Map templateCache; @Autowired TemplateRepository templateRepository; + @Autowired + SvgTemplateService svgTemplateService; @Value("${mosip.certify.vcformat.vc.expiry:true}") boolean shouldHaveDates; @@ -66,8 +75,8 @@ public void initialize() { @Override public String format(JSONObject templateInput, Map defaultSettings) { // TODO: Isn't template name becoming too complex with VC_CONTEXTS & CREDENTIAL_TYPES both? - String templateName = defaultSettings.get("templateName").toString(); - String issuer = defaultSettings.get("issuerURI").toString(); + String templateName = defaultSettings.get(TEMPLATE_NAME).toString(); + String issuer = defaultSettings.get(ISSUER_URI).toString(); String t = templateCache.get(templateName); StringWriter writer = new StringWriter(); // 1. Prepare map @@ -98,6 +107,15 @@ public String format(JSONObject templateInput, Map defaultSettin finalTemplate.put("_esc", new EscapeTool()); // add the issuer value finalTemplate.put("issuer", issuer); + if (defaultSettings.containsKey(SVG_TEMPLATE) && templateName.contains(VCDM2Constants.URL)) { + try { + finalTemplate.put("_renderMethodSVGdigest", + SVGRenderUtils.getDigestMultibase(svgTemplateService.getSvgTemplate( + UUID.fromString((String) defaultSettings.get(SVG_TEMPLATE))).getTemplate())); + } catch (TemplateException e) { + log.error("SVG Template: " + defaultSettings.get(SVG_TEMPLATE) + " not available in DB", e); + } + } if (shouldHaveDates && !(templateInput.has(VCDM2Constants.VALID_FROM) && templateInput.has(VCDM2Constants.VALID_UNITL))) { String time = ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern(Constants.UTC_DATETIME_PATTERN)); diff --git a/certify-service/src/test/java/io/mosip/certify/services/SVGRenderUtilsTest.java b/certify-service/src/test/java/io/mosip/certify/services/SVGRenderUtilsTest.java new file mode 100644 index 00000000..390d19fc --- /dev/null +++ b/certify-service/src/test/java/io/mosip/certify/services/SVGRenderUtilsTest.java @@ -0,0 +1,19 @@ +package io.mosip.certify.services; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class SVGRenderUtilsTest { + + @Test + void getDigestMultibase() { + String svg = """ + + """; + String actual = SVGRenderUtils.getDigestMultibase(svg); + String expected = "z4po9QkJj1fhMt6cxHSnDnAUat4PEVrerUGGsPHLxJnK5"; + assertEquals(expected, actual); + } + +} \ No newline at end of file