diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java index 3f02a85..76e75d8 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java @@ -115,12 +115,12 @@ public class Assertion extends Credential { return found; } } - } - // check external type - if (validateIri(typeNode)) { - return External; - } + // check external type + if (validateIri(typeNode)) { + return External; + } + } return Unknown; } diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/jsonld/probe/GraphFetcherProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/jsonld/probe/GraphFetcherProbe.java index b5958e1..9d5cce1 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/jsonld/probe/GraphFetcherProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/jsonld/probe/GraphFetcherProbe.java @@ -3,7 +3,6 @@ package org.oneedtech.inspect.vc.jsonld.probe; import static org.oneedtech.inspect.vc.Assertion.ValueType.DATA_URI_OR_URL; import java.io.IOException; -import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.List; @@ -27,7 +26,6 @@ import org.oneedtech.inspect.vc.Validation; import org.oneedtech.inspect.vc.jsonld.JsonLdGeneratedObject; import org.oneedtech.inspect.vc.probe.CredentialParseProbe; import org.oneedtech.inspect.vc.resource.UriResourceFactory; -import org.oneedtech.inspect.vc.util.CachingDocumentLoader; import org.oneedtech.inspect.vc.util.JsonNodeUtil; import org.oneedtech.inspect.vc.util.PrimitiveValueValidator; @@ -38,8 +36,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.google.common.io.Resources; -import foundation.identity.jsonld.ConfigurableDocumentLoader; - /** * Probe for fetching all elements in the graph for Open Badges 2.0 validation * Contains the fetch part of "VALIDATE_TYPE_PROPERTY" task in python implementation, as well as the "FLATTEN_EMBEDDED_RESOURCE" task @@ -72,47 +68,10 @@ public class GraphFetcherProbe extends Probe { // flatten embeded resource if (validation.isAllowFlattenEmbeddedResource()) { - if (!node.isTextual()) { - if (!node.isObject()) { - return error("Property " + validation.getName() + " referenced from " + assertion.getJson().toString() + " is not a JSON object or string as expected", ctx); - } - - JsonNode idNode = node.get("id"); - if (idNode == null) { - // add a new node to the graph - UUID newId = UUID.randomUUID(); - JsonNode merged = createNewJson(ctx, "{\"id\": \"_:" + newId + "\"}"); - ctx.addGeneratedObject(new JsonLdGeneratedObject(JsonLDCompactionProve.getId(newId.toString()), merged.toString())); - - // update existing node with new id - updateNode(validation, idNode, ctx); - - return warning("Node id missing at " + node.toString() + ". A blank node ID has been assigned", ctx); - } else if (!idNode.isTextual() || !PrimitiveValueValidator.validateIri(idNode)) { - return error("Embedded JSON object at " + node.asText() + " has no proper assigned id.", ctx); - } else if (assertion.getCredentialType() == Type.Assertion && !PrimitiveValueValidator.validateUrl(idNode)) { - if (!isUrn(idNode)) { - logger.info("ID format for " + idNode.toString() + " at " + assertion.getCredentialType() + " not in an expected HTTP or URN:UUID scheme"); - } - - // add a new node to the graph - JsonNode merged = createNewJson(ctx, node); - ctx.addGeneratedObject(new JsonLdGeneratedObject(JsonLDCompactionProve.getId(idNode.asText().strip()), merged.toString())); - - // update existing node with new id - updateNode(validation, idNode, ctx); - - } else { - - // update existing node with new id - updateNode(validation, idNode, ctx); - - // fetch node and add it to the graph - result = fetchNode(ctx, result, idNode); - } - } + result = flatten(ctx, result, root, node, validation); } + // fetch List nodeList = JsonNodeUtil.asNodeList(node); for (JsonNode childNode : nodeList) { if (shouldFetch(childNode, validation)) { @@ -125,6 +84,60 @@ public class GraphFetcherProbe extends Probe { return success(ctx); } + private ReportItems flatten(RunContext ctx, ReportItems result, JsonNode parentNode, JsonNode node, Validation validation) throws URISyntaxException, Exception { + if (!node.isTextual()) { + if (!node.isObject()) { + result = new ReportItems(List.of(result, error("Property " + validation.getName() + " referenced from " + assertion.getJson().toString() + " is not a JSON object or string as expected", ctx))); + } + + JsonNode idNode = node.get("id"); + if (idNode == null) { + // add a new node to the graph + UUID newId = UUID.randomUUID(); + JsonNode merged = createNewJson(ctx, "{\"id\": \"_:" + newId + "\"}"); + ctx.addGeneratedObject(new JsonLdGeneratedObject(JsonLDCompactionProve.getId(newId.toString()), merged.toString())); + + // update existing node with new id + updateNode(validation, parentNode.get("id").asText().strip(), idNode, ctx); + + return warning("Node id missing at " + node.toString() + ". A blank node ID has been assigned", ctx); + } else if (!idNode.isTextual() || !PrimitiveValueValidator.validateIri(idNode)) { + return new ReportItems(List.of(result, error("Embedded JSON object at " + node.asText() + " has no proper assigned id.", ctx))); + } else { // if (assertion.getCredentialType() == Type.Assertion && !PrimitiveValueValidator.validateUrl(idNode)) { + if (!isUrn(idNode)) { + logger.info("ID format for " + idNode.toString() + " at " + assertion.getCredentialType() + " not in an expected HTTP or URN:UUID scheme"); + } + + // add a new node to the graph + JsonNode merged = createNewJson(ctx, node); + ctx.addGeneratedObject(new JsonLdGeneratedObject(JsonLDCompactionProve.getId(idNode.asText().strip()), merged.toString())); + + // update existing node with new id + updateNode(validation, parentNode.get("id").asText().strip(), idNode, ctx); + + // } else { + // // update existing node with new id + // updateNode(validation, idNode, ctx); + + // // fetch node and add it to the graph + // result = new ReportItems(List.of(result, fetchNode(ctx, result, idNode))); + } + + // recursive call + List flattenValidations = Type.valueOf(node.get("type")).getValidations().stream() + .filter(val -> val.getType() == ValueType.ID && val.isAllowFlattenEmbeddedResource()) + .filter(val -> node.hasNonNull(val.getName())) + .collect(Collectors.toList()); + + for (Validation val : flattenValidations) { + if (node.hasNonNull(val.getName())) { + result = new ReportItems(List.of(result, flatten(ctx, result, node, node.get(val.getName()), val))); + } + } + } + return result; + } + private ReportItems fetchNode(RunContext ctx, ReportItems result, JsonNode idNode) throws URISyntaxException, Exception, JsonProcessingException, JsonMappingException { System.out.println("fetchNode " + idNode.asText().strip()); @@ -165,8 +178,8 @@ public class GraphFetcherProbe extends Probe { (validation.isAllowDataUri() || ValueType.IRI.getValidationFunction().apply(node)); } - private void updateNode(Validation validation, JsonNode idNode, RunContext ctx) throws IOException { - JsonLdGeneratedObject jsonLdGeneratedObject = ctx.getGeneratedObject(JsonLDCompactionProve.getId(assertion)); + private void updateNode(Validation validation, String parentId, JsonNode idNode, RunContext ctx) throws IOException { + JsonLdGeneratedObject jsonLdGeneratedObject = ctx.getGeneratedObject(JsonLDCompactionProve.getId(parentId)); JsonNode merged = createNewJson(ctx, jsonLdGeneratedObject.getJson(), "{\"" + validation.getName() + "\": \"" + idNode.asText().strip() + "\"}"); jsonLdGeneratedObject.setJson(merged.toString()); diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ExpirationProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ExpirationProbe.java index 01e6fb0..c616015 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ExpirationProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ExpirationProbe.java @@ -26,7 +26,7 @@ public class ExpirationProbe extends Probe { * and the expiration date is prior to the current date, the credential has expired. */ JsonNode node = crd.getJson().get(crd.getExpiresAtPropertyName()); - if(node != null) { + if(node != null && !node.isNull()) { try { ZonedDateTime expirationDate = ZonedDateTime.parse(node.textValue()); if (ZonedDateTime.now().isAfter(expirationDate)) {