Added image validation
This commit is contained in:
parent
d3667e580c
commit
60e0187052
@ -146,7 +146,9 @@ public class Assertion extends Credential {
|
||||
TEXT(PrimitiveValueValidator::validateText),
|
||||
TEXT_OR_NUMBER(PrimitiveValueValidator::validateTextOrNumber),
|
||||
URL(PrimitiveValueValidator::validateUrl),
|
||||
URL_AUTHORITY(PrimitiveValueValidator::validateUrlAuthority);
|
||||
URL_AUTHORITY(PrimitiveValueValidator::validateUrlAuthority),
|
||||
|
||||
IMAGE(null);
|
||||
|
||||
private final Function<JsonNode, Boolean> validationFunction;
|
||||
|
||||
@ -173,7 +175,8 @@ public class Assertion extends Credential {
|
||||
new Validation.Builder().name("expires").type(ValueType.DATETIME).required(false).build(),
|
||||
new Validation.Builder().name("image").type(ValueType.ID).required(false).allowRemoteUrl(true).expectedType(Type.Image).fetch(false).allowDataUri(false).build(),
|
||||
new Validation.Builder().name("narrative").type(ValueType.MARKDOWN_TEXT).required(false).build(),
|
||||
new Validation.Builder().name("evidence").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.Evidence).many(true).fetch(false).required(false).build()
|
||||
new Validation.Builder().name("evidence").type(ValueType.ID).allowRemoteUrl(true).expectedType(Type.Evidence).many(true).fetch(false).required(false).build(),
|
||||
new Validation.Builder().name("image").type(ValueType.IMAGE).required(false).many(false).allowDataUri(false).build()
|
||||
))
|
||||
.put(Type.BadgeClass, List.of(
|
||||
new Validation.Builder().name("id").type(ValueType.IRI).required(true).build(),
|
||||
|
@ -0,0 +1,65 @@
|
||||
package org.oneedtech.inspect.vc.probe;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.oneedtech.inspect.core.probe.RunContext;
|
||||
import org.oneedtech.inspect.core.report.ReportItems;
|
||||
import org.oneedtech.inspect.util.resource.MimeType;
|
||||
import org.oneedtech.inspect.util.resource.UriResource;
|
||||
import org.oneedtech.inspect.vc.Validation;
|
||||
import org.oneedtech.inspect.vc.util.PrimitiveValueValidator;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public class ValidationImagePropertyProbe extends ValidationPropertyProbe {
|
||||
|
||||
public ValidationImagePropertyProbe(Validation validation) {
|
||||
super(validation);
|
||||
}
|
||||
|
||||
public ValidationImagePropertyProbe(Validation validation, boolean fullValidate) {
|
||||
super(validation, fullValidate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReportItems reportForNonExistentProperty(JsonNode node, RunContext ctx) {
|
||||
return notRun("Could not load and validate image in node " + node.toString(), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReportItems validate(JsonNode node, RunContext ctx) {
|
||||
if (node.isArray()) {
|
||||
return error("many images not allowed", ctx);
|
||||
}
|
||||
String url = node.isObject() ? node.get("id").asText() : node.asText();
|
||||
if (PrimitiveValueValidator.validateDataUri(node)) {
|
||||
if (!validation.isAllowDataUri()) {
|
||||
return error("Image in node " + node + " may not be a data URI.", ctx);
|
||||
}
|
||||
|
||||
// check mime types
|
||||
final Pattern pattern = Pattern.compile("(^data):([^,]{0,}?)?(base64)?,(.*$)");
|
||||
final Matcher matcher = pattern.matcher(url);
|
||||
if (matcher.matches()) {
|
||||
MimeType mimeType = new MimeType(matcher.toMatchResult().group(2));
|
||||
if (!allowedMimeTypes.contains(mimeType)) {
|
||||
return error("Data URI image does not declare any of the allowed PNG or SVG mime types in " + node.asText(), ctx);
|
||||
}
|
||||
}
|
||||
} else if (!url.isEmpty()) {
|
||||
try {
|
||||
UriResource uriResource = resolveUriResource(ctx, url);
|
||||
// TODO: load resource from cache
|
||||
// TODO: check accept type -> 'Accept': 'application/ld+json, application/json, image/png, image/svg+xml'
|
||||
uriResource.asByteSource();
|
||||
} catch (Throwable t) {
|
||||
return fatal(t.getMessage(), ctx);
|
||||
}
|
||||
}
|
||||
return success(ctx);
|
||||
}
|
||||
|
||||
private static final List<MimeType> allowedMimeTypes = List.of(MimeType.IMAGE_PNG, MimeType.IMAGE_SVG);
|
||||
}
|
@ -122,7 +122,7 @@ public class ValidationPropertyProbe extends PropertyProbe {
|
||||
return error("Node " + node.toString() + " has " + validation.getName() +" property value `" + childNode.toString() + "` that appears not to be in URI format", ctx);
|
||||
} else {
|
||||
// fetch
|
||||
UriResource uriResource = resolveUriResource(ctx, childNode);
|
||||
UriResource uriResource = resolveUriResource(ctx, childNode.asText());
|
||||
|
||||
result = new ReportItems(List.of(result, new CredentialParseProbe().run(uriResource, ctx)));
|
||||
if (!result.contains(Outcome.FATAL, Outcome.EXCEPTION)) {
|
||||
@ -152,8 +152,8 @@ public class ValidationPropertyProbe extends PropertyProbe {
|
||||
return result.size() > 0 ? result : success(ctx);
|
||||
}
|
||||
|
||||
private UriResource resolveUriResource(RunContext ctx, JsonNode childNode) throws URISyntaxException {
|
||||
URI uri = new URI(childNode.asText());
|
||||
protected UriResource resolveUriResource(RunContext ctx, String url) throws URISyntaxException {
|
||||
URI uri = new URI(url);
|
||||
UriResource initialUriResource = new UriResource(uri);
|
||||
UriResource uriResource = initialUriResource;
|
||||
|
||||
@ -182,7 +182,7 @@ public class ValidationPropertyProbe extends PropertyProbe {
|
||||
return new ReportItems(results);
|
||||
}
|
||||
|
||||
private void flattenEmbeddedResource() {
|
||||
private void flattenEmbeddedResource(JsonNode node, RunContext ctx) {
|
||||
/*
|
||||
try:
|
||||
node_id = task_meta['node_id']
|
||||
@ -249,80 +249,5 @@ public class ValidationPropertyProbe extends PropertyProbe {
|
||||
*/
|
||||
}
|
||||
|
||||
private void validateImage() {
|
||||
/*
|
||||
def validate_image(state, task_meta, **options):
|
||||
try:
|
||||
node_id = task_meta.get('node_id')
|
||||
node_path = task_meta.get('node_path')
|
||||
prop_name = task_meta.get('prop_name', 'image')
|
||||
node_class = task_meta.get('node_class')
|
||||
required = bool(task_meta.get('required', False))
|
||||
if node_id:
|
||||
node = get_node_by_id(state, node_id)
|
||||
node_path = [node_id]
|
||||
else:
|
||||
node = get_node_by_path(state, node_path)
|
||||
|
||||
if options.get('cache_backend'):
|
||||
session = requests_cache.CachedSession(
|
||||
backend=options['cache_backend'], expire_after=options.get('cache_expire_after', 300))
|
||||
else:
|
||||
session = requests.Session()
|
||||
except (IndexError, TypeError, KeyError):
|
||||
raise TaskPrerequisitesError()
|
||||
|
||||
actions = []
|
||||
|
||||
image_val = node.get(prop_name)
|
||||
|
||||
if image_val is None:
|
||||
return task_result(not required, "Could not load and validate image in node {}".format(abv_node(node_id, node_path)))
|
||||
if isinstance(image_val, six.string_types):
|
||||
url = image_val
|
||||
elif isinstance(image_val, dict):
|
||||
url = image_val.get('id')
|
||||
elif isinstance(image_val, list):
|
||||
return task_result(False, "many images not allowed")
|
||||
else:
|
||||
raise TypeError("Could not interpret image property value {}".format(
|
||||
abbreviate_value(image_val)
|
||||
))
|
||||
if is_data_uri(url):
|
||||
if task_meta.get('allow_data_uri', False) is False:
|
||||
return task_result(False, "Image in node {} may not be a data URI.".format(abv_node(node_id, node_path)))
|
||||
try:
|
||||
mimetypes = re.match(r'(?P<scheme>^data):(?P<mimetypes>[^,]{0,}?)?(?P<encoding>base64)?,(?P<data>.*$)', url).group(
|
||||
'mimetypes')
|
||||
if 'image/png' not in mimetypes and 'image/svg+xml' not in mimetypes:
|
||||
raise ValueError("Disallowed filetype")
|
||||
except (AttributeError, ValueError,):
|
||||
return task_result(
|
||||
False, "Data URI image does not declare any of the allowed PNG or SVG mime types in {}".format(
|
||||
abv_node(node_id, node_path))
|
||||
)
|
||||
elif url:
|
||||
existing_file = state.get('input', {}).get('original_json', {}).get(url)
|
||||
if existing_file:
|
||||
return task_result(True, "Image resource already stored for url {}".format(abbreviate_value(url)))
|
||||
else:
|
||||
try:
|
||||
result = session.get(
|
||||
url, headers={'Accept': 'application/ld+json, application/json, image/png, image/svg+xml'}
|
||||
)
|
||||
result.raise_for_status()
|
||||
content_type = result.headers['content-type']
|
||||
encoded_body = base64.b64encode(result.content)
|
||||
data_uri = "data:{};base64,{}".format(content_type, encoded_body)
|
||||
|
||||
except (requests.ConnectionError, requests.HTTPError, KeyError):
|
||||
return task_result(False, "Could not fetch image at {}".format(url))
|
||||
else:
|
||||
actions.append(store_original_resource(url, data_uri))
|
||||
|
||||
return task_result(True, "Validated image for node {}".format(abv_node(node_id, node_path)), actions)
|
||||
|
||||
*/
|
||||
}
|
||||
public static final String ID = ValidationPropertyProbe.class.getSimpleName();
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ public class ValidationPropertyProbeFactory {
|
||||
if (validation.getType() == ValueType.RDF_TYPE) {
|
||||
return new ValidationRdfTypePropertyProbe(validation, fullValidate);
|
||||
}
|
||||
if (validation.getType() == ValueType.IMAGE) {
|
||||
return new ValidationImagePropertyProbe(validation);
|
||||
}
|
||||
return new ValidationPropertyProbe(validation, fullValidate);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user