diff --git a/hcx-qr-code-generator/pom.xml b/hcx-qr-code-generator/pom.xml
new file mode 100644
index 000000000..212fe42bb
--- /dev/null
+++ b/hcx-qr-code-generator/pom.xml
@@ -0,0 +1,121 @@
+
+ 4.0.0
+
+ org.swasth
+ hcx-platform
+ 1.0-SNAPSHOT
+
+
+ hcx-qr-code-generator
+ jar
+
+ 17
+ 17
+ 17
+
+
+ hcx-qr-code-generator
+ http://maven.apache.org
+
+
+
+ io.jsonwebtoken
+ jjwt
+ 0.9.1
+
+
+ javax.xml.bind
+ jaxb-api
+ 2.3.1
+
+
+ com.google.zxing
+ core
+ 3.5.1
+
+
+ com.google.zxing
+ javase
+ 3.4.0
+
+
+ com.google.code.gson
+ gson
+ 2.10.1
+
+
+ org.freemarker
+ freemarker
+ 2.3.31
+
+
+ org.swasth
+ hcx-common
+ 1.0-SNAPSHOT
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+
+ ${java.target.runtime}
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.5.0
+
+
+ package
+
+ shade
+
+
+
+
+
+ org.swasth.HcxQRCodeGenerator
+
+
+
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.7
+
+
+ default-prepare-agent
+
+ prepare-agent
+
+
+
+ default-report
+ prepare-package
+
+ report
+
+
+
+
+
+
+
diff --git a/hcx-qr-code-generator/src/main/java/org/swasth/HcxQRCodeGenerator.java b/hcx-qr-code-generator/src/main/java/org/swasth/HcxQRCodeGenerator.java
new file mode 100644
index 000000000..d2a423bd4
--- /dev/null
+++ b/hcx-qr-code-generator/src/main/java/org/swasth/HcxQRCodeGenerator.java
@@ -0,0 +1,142 @@
+package org.swasth;
+
+import com.google.gson.Gson;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import com.google.zxing.common.BitMatrix;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+import org.apache.commons.io.IOUtils;
+import org.swasth.service.EncDeCode;
+import org.swasth.utils.JWSUtils;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class HcxQRCodeGenerator {
+ private static final Logger logger = Logger.getLogger(String.valueOf(HcxQRCodeGenerator.class));
+ private static int width;
+ private static int height;
+ private static String privatekey;
+
+ static {
+ try {
+ loadConfig();
+ } catch (Exception e) {
+ logger.info(e.getMessage());
+ }
+ }
+
+ private static void loadConfig() {
+ Yaml yaml = new Yaml();
+ try (InputStream inputStream = HcxQRCodeGenerator.class.getResourceAsStream("/application.yml")) {
+ Map config = yaml.load(inputStream);
+ Map qrCodeConfig = (Map) config.get("qr_code");
+ width = parseWidthHeight((String) qrCodeConfig.get("width"));
+ height = parseWidthHeight((String) qrCodeConfig.get("height"));
+ privatekey = resolvePlaceholder((String) qrCodeConfig.get("private_key"));
+ }catch (Exception e){
+ logger.info(e.getMessage());
+ }
+ }
+
+ private static int parseWidthHeight(String value) {
+ if (value.startsWith("${") && value.endsWith("}")) {
+ Pattern pattern = Pattern.compile("\\$\\{(.+?):(\\d+)}");
+ Matcher matcher = pattern.matcher(value);
+ if (matcher.find()) {
+ return Integer.parseInt(matcher.group(2));
+ }
+ }
+ return Integer.parseInt(value);
+ }
+
+ protected static String resolvePlaceholder(String value) {
+ if (value.startsWith("${") && value.endsWith("}")) {
+ int colonIndex = value.indexOf(':');
+ if (colonIndex != -1) {
+ return value.substring(colonIndex + 1, value.length() - 1);
+ }
+ }
+ return value;
+ }
+
+ public static void main(String[] args) throws TemplateException, IOException, NoSuchAlgorithmException, InvalidKeySpecException, WriterException, URISyntaxException {
+ if (args.length > 0) {
+ String json = args[0];
+ Gson gson = new Gson();
+ Map map = gson.fromJson(json, HashMap.class);
+ logger.info("Map received from command line argument:");
+ String certificate = IOUtils.toString(new URI(privatekey), StandardCharsets.UTF_8);
+ generateQrToken((Map) map.get("payload"), certificate);
+ } else {
+ logger.info("No input to process");
+ }
+ }
+
+ private static String getPrivateKey(String privateKey) {
+ privateKey = privateKey
+ .replace("-----BEGIN PRIVATE KEY-----", "")
+ .replace("-----END PRIVATE KEY-----", "")
+ .replaceAll("\\s+", "");
+ return privateKey;
+ }
+
+ private static String generateQrToken(Map requestBody, String privateKey) throws TemplateException, IOException, WriterException, NoSuchAlgorithmException, InvalidKeySpecException {
+ Map headers = new HashMap<>();
+ String jwsToken = JWSUtils.generate(headers, requestBody, HcxQRCodeGenerator.getPrivateKey(privateKey));
+ String participantCode = null;
+ if (requestBody.containsKey("participantCode")) {
+ participantCode = (String) requestBody.get("participantCode");
+ }
+ logger.info("QR Token generated");
+ String payload = createVerifiableCredential(requestBody, jwsToken);
+ generateQRCode(EncDeCode.encodePayload(payload), participantCode);
+ return payload;
+ }
+ private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
+ private static String createVerifiableCredential(Map payload, String proofValue) throws IOException, TemplateException {
+ Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
+ cfg.setClassForTemplateLoading(HcxQRCodeGenerator.class, "/templates");
+ Template template = cfg.getTemplate("verifiable-credential.ftl");
+ LocalDateTime issuanceDate = LocalDateTime.now();
+ LocalDateTime expirationDate = LocalDateTime.now().plusYears(1);
+ Map data = new HashMap<>();
+ data.put("issuanceDate", formatter.format(issuanceDate));
+ data.put("expirationDate", formatter.format(expirationDate));
+ data.put("subjectId", UUID.randomUUID());
+ data.put("payload", new Gson().toJson(payload));
+ data.put("proofCreated", LocalDateTime.now());
+ data.put("proofValue", proofValue);
+ StringWriter out = new StringWriter();
+ template.process(data, out);
+ return out.toString();
+ }
+
+ private static void generateQRCode(String content, String participantCode) throws WriterException, IOException {
+ MultiFormatWriter writer = new MultiFormatWriter();
+ BitMatrix matrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height);
+ String currentDir = System.getProperty("user.dir");
+ Path path = FileSystems.getDefault().getPath(currentDir + "/" + participantCode + "_qr_code_" + System.currentTimeMillis() + ".png");
+ MatrixToImageWriter.writeToPath(matrix, "PNG", path);
+ logger.info("QR code image generated and saved to: " + path.toAbsolutePath());
+ }
+}
diff --git a/hcx-qr-code-generator/src/main/java/org/swasth/service/EncDeCode.java b/hcx-qr-code-generator/src/main/java/org/swasth/service/EncDeCode.java
new file mode 100644
index 000000000..078e71f67
--- /dev/null
+++ b/hcx-qr-code-generator/src/main/java/org/swasth/service/EncDeCode.java
@@ -0,0 +1,26 @@
+package org.swasth.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import static org.swasth.common.utils.JSONUtils.deserialize;
+
+public class EncDeCode {
+ private static final Logger logger = Logger.getLogger(String.valueOf(EncDeCode.class));
+ public static String encodePayload(String payload) {
+ String base64EncodedSignature = Base64.getEncoder().encodeToString(payload.getBytes());
+ logger.info("Encoded Payload");
+ return base64EncodedSignature;
+ }
+
+ public static Map decodePayload(String payload) throws JsonProcessingException {
+ byte[] decodedBytes = Base64.getDecoder().decode(payload);
+ String decodedString = new String(decodedBytes, StandardCharsets.UTF_8);
+ return deserialize(decodedString, Map.class);
+ }
+
+}
diff --git a/hcx-qr-code-generator/src/main/java/org/swasth/service/VerifyQrCode.java b/hcx-qr-code-generator/src/main/java/org/swasth/service/VerifyQrCode.java
new file mode 100644
index 000000000..f43f44e96
--- /dev/null
+++ b/hcx-qr-code-generator/src/main/java/org/swasth/service/VerifyQrCode.java
@@ -0,0 +1,49 @@
+package org.swasth.service;
+
+import org.apache.commons.io.IOUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Map;
+import java.util.logging.Logger;
+
+public class VerifyQrCode {
+ private static final Logger logger = Logger.getLogger(String.valueOf(VerifyQrCode.class));
+
+ public static Map getToken(Map payload) throws CertificateException, IOException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
+ String publicKeyUrl = "https://raw.githubusercontent.com/Swasth-Digital-Health-Foundation/hcx-platform/main/hcx-apis/src/test/resources/examples/test-keys/public-key.pem";
+ Map token = (Map) payload.get("proof");
+ if (token.containsKey("proofValue")) {
+ String jwsToken = (String) token.get("proofValue");
+ boolean isSignatureValid = isValidSignature(jwsToken, publicKeyUrl);
+ logger.info(isSignatureValid + " Valid Signature");
+ } else logger.info("proofValue is empty or null");
+ return token;
+ }
+
+ public static boolean isValidSignature(String payload, String publicKeyUrl) throws IOException, CertificateException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ String certificate = IOUtils.toString(new URL(publicKeyUrl), StandardCharsets.UTF_8);
+ byte[] certificateBytes = certificate.getBytes(StandardCharsets.UTF_8);
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ InputStream stream = new ByteArrayInputStream(certificateBytes);
+ Certificate cert = cf.generateCertificate(stream);
+ PublicKey publicKey = cert.getPublicKey();
+ String[] parts = payload.split("\\.");
+ String data = String.join(".", Arrays.copyOfRange(parts, 0, 2));
+ Signature sig = Signature.getInstance("SHA256withRSA");
+ sig.initVerify(publicKey);
+ sig.update(data.getBytes(StandardCharsets.UTF_8));
+ byte[] decodedSignature = Base64.getUrlDecoder().decode(parts[2]);
+ return sig.verify(decodedSignature);
+ }
+
+}
diff --git a/hcx-qr-code-generator/src/main/java/org/swasth/utils/JWSUtils.java b/hcx-qr-code-generator/src/main/java/org/swasth/utils/JWSUtils.java
new file mode 100644
index 000000000..93eaedca1
--- /dev/null
+++ b/hcx-qr-code-generator/src/main/java/org/swasth/utils/JWSUtils.java
@@ -0,0 +1,21 @@
+package org.swasth.utils;
+
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+import java.util.Map;
+
+public class JWSUtils {
+ public static String generate(Map headers, Map payload, String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
+ byte[] privateKeyDecoded = Base64.getDecoder().decode(privateKey);
+ PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKeyDecoded);
+ PrivateKey rsaPrivateKey = KeyFactory.getInstance("RSA").generatePrivate(spec);
+ return Jwts.builder().setHeader(headers).setClaims(payload).signWith(SignatureAlgorithm.RS256, rsaPrivateKey).compact();
+ }
+}
diff --git a/hcx-qr-code-generator/src/main/resources/application.yml b/hcx-qr-code-generator/src/main/resources/application.yml
new file mode 100644
index 000000000..30b11b3ea
--- /dev/null
+++ b/hcx-qr-code-generator/src/main/resources/application.yml
@@ -0,0 +1,4 @@
+qr_code:
+ width: ${width:150}
+ height: ${height:150}
+ private_key: ${private_key:https://raw.githubusercontent.com/Swasth-Digital-Health-Foundation/hcx-platform/main/hcx-apis/src/test/resources/examples/test-keys/private-key.pem}
diff --git a/hcx-qr-code-generator/src/main/resources/templates/verifiable-credential.ftl b/hcx-qr-code-generator/src/main/resources/templates/verifiable-credential.ftl
new file mode 100644
index 000000000..e9829f1ce
--- /dev/null
+++ b/hcx-qr-code-generator/src/main/resources/templates/verifiable-credential.ftl
@@ -0,0 +1,23 @@
+{
+ "@context": [
+ "https://www.w3.org/2018/credentials/v1",
+ "https://www.w3.org/2018/credentials/examples/v1"
+ ],
+ "id": "http://hcxprotocol.io/credentials/3732",
+ "type": ["VerifiableCredential"],
+ "issuer": "https://hcxprotocol.io/participant/565049",
+ "issuanceDate": "${issuanceDate}",
+ "expirationDate": "${expirationDate}",
+ "preferredHCXPath": "http://hcx.swasth.app/api/v0.8/",
+ "credentialSubject": {
+ "id": "${subjectId}",
+ "payload": ${payload}
+ },
+ "proof": {
+ "type": "Ed25519Signature2020",
+ "created": "${proofCreated}",
+ "verificationMethod": "https://hcxprotocol.io/issuers/565049#key-1",
+ "proofPurpose": "assertionMethod",
+ "proofValue": "${proofValue}"
+ }
+}
diff --git a/hcx-qr-code-generator/src/test/java/org/swasth/HcxQRCodeGeneratorTest.java b/hcx-qr-code-generator/src/test/java/org/swasth/HcxQRCodeGeneratorTest.java
new file mode 100644
index 000000000..a07644b5a
--- /dev/null
+++ b/hcx-qr-code-generator/src/test/java/org/swasth/HcxQRCodeGeneratorTest.java
@@ -0,0 +1,130 @@
+package org.swasth;
+
+
+import org.junit.Test;
+import org.swasth.service.EncDeCode;
+import org.swasth.service.VerifyQrCode;
+import org.swasth.utils.JWSUtils;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+
+public class HcxQRCodeGeneratorTest {
+
+ HcxQRCodeGenerator hcxQRCodeGenerator = new HcxQRCodeGenerator();
+
+ VerifyQrCode verifyQRCode = new VerifyQrCode();
+
+ EncDeCode encDeCode = new EncDeCode();
+
+
+ JWSUtils jwsUtils = new JWSUtils();
+
+
+ @Test
+ public void test_hcx_qr_generator_success() throws Exception {
+ String[] args = {"{\"payload\":{\"participantCode\":\"test_user_55.yopmail@swasth-hcx\",\"email\":\"test_user_555@yopmail.com\",\"mobile\":\"9899912323\"}}"};
+ hcxQRCodeGenerator.main(args);
+ }
+
+ @Test
+ public void test_hcx_qr_generator() throws Exception {
+ String[] args = {"{\"payload\":{\"email\":\"test_user_555@yopmail.com\",\"mobile\":\"9899912323\"}}"};
+ hcxQRCodeGenerator.main(args);
+ }
+
+ @Test
+ public void test_hcx_qr_generator_no_input_exception() throws Exception {
+ String[] args = {};
+ HcxQRCodeGenerator.main(args);
+ }
+
+ @Test
+ public void test_decode() throws Exception {
+ String encodedString = "ew0KICAiQGNvbnRleHQiOiBbDQogICAgImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIiwNCiAgICAiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvZXhhbXBsZXMvdjEiDQogIF0sDQogICJpZCI6ICJodHRwOi8vaGN4cHJvdG9jb2wuaW8vY3JlZGVudGlhbHMvMzczMiIsDQogICJ0eXBlIjogWyJWZXJpZmlhYmxlQ3JlZGVudGlhbCJdLA0KICAiaXNzdWVyIjogImh0dHBzOi8vaGN4cHJvdG9jb2wuaW8vcGFydGljaXBhbnQvNTY1MDQ5IiwNCiAgImlzc3VhbmNlRGF0ZSI6ICIyMDI0LTAyLTE5VDEyOjMzOjU1LjI3OTkzNjMiLA0KICAiZXhwaXJhdGlvbkRhdGUiOiAiMjAyNS0wMi0xOVQxMjozMzo1NS4yNzk5MzYzIiwNCiAgInByZWZlcnJlZEhDWFBhdGgiOiAiaHR0cDovL2hjeC5zd2FzdGguYXBwL2FwaS92MC44LyIsDQogICJjcmVkZW50aWFsU3ViamVjdCI6IHsNCiAgICAiaWQiOiAiY2I0YzE5MjQtOGUzZi00NTgxLThjZWEtNDg4ZmMxOTBiZTA3IiwNCiAgICAicGF5bG9hZCI6IHsicGFydGljaXBhbnRDb2RlIjoidGVzdF91c2VyXzU1LnlvcG1haWxAc3dhc3RoLWhjeCIsImVtYWlsIjoidGVzdF91c2VyXzU1NUB5b3BtYWlsLmNvbSIsIm1vYmlsZSI6Ijk4OTk5MTIzMjMifQ0KICB9LA0KICAicHJvb2YiOiB7DQogICAgInR5cGUiOiAiRWQyNTUxOVNpZ25hdHVyZTIwMjAiLA0KICAgICJjcmVhdGVkIjogIjIwMjQtMDItMTlUMTI6MzM6NTUuMjg0MjMxMTAwIiwNCiAgICAidmVyaWZpY2F0aW9uTWV0aG9kIjogImh0dHBzOi8vaGN4cHJvdG9jb2wuaW8vaXNzdWVycy81NjUwNDkja2V5LTEiLA0KICAgICJwcm9vZlB1cnBvc2UiOiAiYXNzZXJ0aW9uTWV0aG9kIiwNCiAgICAicHJvb2ZWYWx1ZSI6ICJleUpoYkdjaU9pSlNVekkxTmlKOS5leUp3WVhKMGFXTnBjR0Z1ZEVOdlpHVWlPaUowWlhOMFgzVnpaWEpmTlRVdWVXOXdiV0ZwYkVCemQyRnpkR2d0YUdONElpd2laVzFoYVd3aU9pSjBaWE4wWDNWelpYSmZOVFUxUUhsdmNHMWhhV3d1WTI5dElpd2liVzlpYVd4bElqb2lPVGc1T1RreE1qTXlNeUo5Lkk4c2VZMWQ0eUZ6NE5mX3RmZlkxOF9mZWpxZTFfaEJ5T3JsVnJENEMxUDNyQ19WamNhOUhHN19lRkJDUHFIdWh6RXJoeFJUb0FWTzZaMnJYVWNOUmhjc3diS2VWZFpVUFVfb3V4QXJCdUJZUVl4dlFybHNVX25vc2huT0pQYUZlNFk4bmNaWURWYnpPRjRXeVpsUFk3VDZ5UXBJMTJDUFIyMEJYVjhqOFFiaENkMEZ5eW9LN051VVhIcWlYZlFBeEY5YkJEamtoTlNNZzZ1Tjc2dFk1OEI3T0xVakhNYkUzOWU0QTNnQ3pTX0lNNk5uYzdaMHQ4ektsNXJTTFl1elptXzFCWDBPTXc4OGY0WVZENEF6X1FqWDVtNkNzZmVjMWk2X3NHZFZXbzN5em5rdXJ2SVNMdlZLaWNXRFFyMEdkVUVFazg1RUpEX3A5OVhmMktxNTBpQSINCiAgfQ0KfQ0K";
+ encDeCode.decodePayload(encodedString);
+ }
+
+ @Test
+ public void test_isValid_signature_success() throws Exception {
+ String publicKeyUrl = "https://raw.githubusercontent.com/Swasth-Digital-Health-Foundation/hcx-platform/main/hcx-apis/src/test/resources/examples/test-keys/public-key.pem";
+ Map jsonData = new HashMap<>();
+
+ Map credentialSubject = new HashMap<>();
+ Map proof = new HashMap<>();
+
+ credentialSubject.put("id", "cb4c1924-8e3f-4581-8cea-488fc190be07");
+ Map payload = new HashMap<>();
+ payload.put("participantCode", "test_user_55.yopmail@swasth-hcx");
+ payload.put("email", "test_user_555@yopmail.com");
+ payload.put("mobile", "9899912323");
+ credentialSubject.put("payload", payload);
+
+ proof.put("proofPurpose", "assertionMethod");
+ proof.put("proofValue", "eyJhbGciOiJSUzI1NiJ9.eyJwYXJ0aWNpcGFudENvZGUiOiJ0ZXN0X3VzZXJfNTUueW9wbWFpbEBzd2FzdGgtaGN4IiwiZW1haWwiOiJ0ZXN0X3VzZXJfNTU1QHlvcG1haWwuY29tIiwibW9iaWxlIjoiOTg5OTkxMjMyMyJ9.I8seY1d4yFz4Nf_tffY18_fejqe1_hByOrlVrD4C1P3rC_Vjca9HG7_eFBCPqHuhzErhxRToAVO6Z2rXUcNRhcswbKeVdZUPU_ouxArBuBYQYxvQrlsU_noshnOJPaFe4Y8ncZYDVbzOF4WyZlPY7T6yQpI12CPR20BXV8j8QbhCd0FyyoK7NuUXHqiXfQAxF9bBDjkhNSMg6uN76tY58B7OLUjHMbE39e4A3gCzS_IM6Nnc7Z0t8zKl5rSLYuzZm_1BX0OMw88f4YVD4Az_QjX5m6Csfec1i6_sGdVWo3yznkurvISLvVKicWDQr0GdUEEk85EJD_p99Xf2Kq50iA");
+
+ jsonData.put("@context", Arrays.asList("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"));
+ jsonData.put("type", Collections.singletonList("VerifiableCredential"));
+ jsonData.put("issuanceDate", "2024-02-19T12:33:55.2799363");
+ jsonData.put("expirationDate", "2025-02-19T12:33:55.2799363");
+ jsonData.put("credentialSubject", credentialSubject);
+ jsonData.put("proof", proof);
+ Map verify = verifyQRCode.getToken(jsonData);
+ String token = (String) verify.get("proofValue");
+ boolean assertvalue = verifyQRCode.isValidSignature(token,publicKeyUrl);
+ assertTrue(assertvalue);
+ }
+
+ @Test
+ public void test_isValid_signature_invaild_proofValue_exception() throws Exception {
+ Map jsonData = new HashMap<>();
+ Map proof = new HashMap<>();
+ proof.put("type", "Ed25519Signature2020");
+ proof.put("created", "2024-02-19T12:33:55.284231100");
+ proof.put("verificationMethod", "https://hcxprotocol.io/issuers/565049#key-1");
+ jsonData.put("proof", proof);
+ verifyQRCode.getToken(jsonData);
+ }
+
+ @Test
+ public void testResolvePlaceholder_NoPlaceholder() {
+ String result = HcxQRCodeGenerator.resolvePlaceholder("testValue");
+ assertEquals("testValue", result);
+ }
+
+ @Test
+ public void testResolvePlaceholder_WithColon() {
+ String result = HcxQRCodeGenerator.resolvePlaceholder("${placeholder:value}");
+ assertEquals("value", result);
+ }
+
+ @Test
+ public void testResolvePlaceholder_WithoutColon() {
+ String result = HcxQRCodeGenerator.resolvePlaceholder("${placeholder}");
+ assertEquals("${placeholder}", result);
+ }
+
+ @Test
+ public void testResolvePlaceholder_NotStartingWithDollarAndCurlyBraces() {
+ String result = HcxQRCodeGenerator.resolvePlaceholder("value}");
+ assertEquals("value}", result);
+ }
+
+ @Test
+ public void testResolvePlaceholder_NotEndingWithCurlyBrace() {
+ String result = HcxQRCodeGenerator.resolvePlaceholder("${value");
+ assertEquals("${value", result);
+ }
+
+ @Test
+ public void testResolvePlaceholder_EmptyString() {
+ String result = HcxQRCodeGenerator.resolvePlaceholder("");
+ assertEquals("", result);
+ }
+
+}
diff --git a/hcx-qr-code-generator/src/test/resources/application-test.yml b/hcx-qr-code-generator/src/test/resources/application-test.yml
new file mode 100644
index 000000000..30b11b3ea
--- /dev/null
+++ b/hcx-qr-code-generator/src/test/resources/application-test.yml
@@ -0,0 +1,4 @@
+qr_code:
+ width: ${width:150}
+ height: ${height:150}
+ private_key: ${private_key:https://raw.githubusercontent.com/Swasth-Digital-Health-Foundation/hcx-platform/main/hcx-apis/src/test/resources/examples/test-keys/private-key.pem}
diff --git a/pom.xml b/pom.xml
index 386219fc9..ac7a0aa9e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,6 +25,7 @@
api-gateway
hcx-scheduler-jobs
hcx-onboard
+ hcx-qr-code-generator