Added validations by type

This commit is contained in:
Xavi Aracil 2022-11-28 14:22:15 +01:00
parent 7cd9103001
commit 4267423273
2 changed files with 326 additions and 6 deletions

View File

@ -1,9 +1,10 @@
package org.oneedtech.inspect.vc; package org.oneedtech.inspect.vc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import org.oneedtech.inspect.schema.Catalog; import org.oneedtech.inspect.schema.Catalog;
import org.oneedtech.inspect.schema.SchemaKey; import org.oneedtech.inspect.schema.SchemaKey;
@ -43,6 +44,10 @@ public class Assertion extends Credential {
.toString(); .toString();
} }
public List<Validation> getValidations() {
return validationMap.get(assertionType);
}
private static final Map<CredentialEnum, SchemaKey> schemas = new ImmutableMap.Builder<CredentialEnum, SchemaKey>() private static final Map<CredentialEnum, SchemaKey> schemas = new ImmutableMap.Builder<CredentialEnum, SchemaKey>()
.put(Type.Assertion, Catalog.OB_21_ASSERTION_JSON) .put(Type.Assertion, Catalog.OB_21_ASSERTION_JSON)
.build(); .build();
@ -60,8 +65,27 @@ public class Assertion extends Credential {
public enum Type implements CredentialEnum { public enum Type implements CredentialEnum {
Assertion(List.of("Assertion")), Assertion(List.of("Assertion")),
BadgeClass(List.of("BadgeClass")), BadgeClass(List.of("BadgeClass")),
AlignmentObject(List.of("AlignmentObject")),
Criteria(List.of("Criteria")),
CryptographicKey(List.of("CryptographicKey")),
Endorsement(List.of("Endorsement")),
EndorsementClaim(List.of("EndorsementClaim")),
Evidence(List.of("Evidence")),
ExpectedRecipientProfile(List.of("ExpectedRecipientProfile")),
Extension(List.of("Extension")),
IdentityObject(List.of("IdentityObject")),
Image(List.of("Image")),
Issuer(List.of("Issuer")),
Profile(List.of("Profile")),
RevocationList(List.of("RevocationList")),
VerificationObject(List.of("VerificationObject")),
VerificationObjectAssertion(List.of("VerificationObjectAssertion")),
VerificationObjectIssuer(List.of("VerificationObjectIssuer")),
Unknown(Collections.emptyList()); Unknown(Collections.emptyList());
public static List<Type> primaryObjects = List.of(Assertion, BadgeClass, Issuer, Profile, Endorsement);
private final List<String> allowedTypeValues; private final List<String> allowedTypeValues;
Type(List<String> typeValues) { Type(List<String> typeValues) {
@ -72,11 +96,12 @@ public class Assertion extends Credential {
if(typeNode != null) { if(typeNode != null) {
List<String> values = JsonNodeUtil.asStringList(typeNode); List<String> values = JsonNodeUtil.asStringList(typeNode);
for (String value : values) { for (String value : values) {
if(value.equals("Assertion")) { Type found = Arrays.stream(Type.values())
return Assertion; .filter(type -> value.equals(type.toString()))
} .findFirst()
if(value.equals("BadgeClass")) { .orElse(Unknown);
return BadgeClass; if (found != Unknown) {
return found;
} }
} }
} }
@ -99,5 +124,158 @@ public class Assertion extends Credential {
} }
} }
public enum ValueType {
BOOLEAN,
COMPACT_IRI,
DATA_URI,
DATA_URI_OR_URL,
DATETIME,
EMAIL,
ID,
IDENTITY_HASH,
IRI,
LANGUAGE,
MARKDOWN_TEXT,
RDF_TYPE,
TELEPHONE,
TEXT,
TEXT_OR_NUMBER,
URL,
URL_AUTHORITY;
public static List<ValueType> primitives = List.of(BOOLEAN, DATA_URI_OR_URL, DATETIME, ID, IDENTITY_HASH, IRI, LANGUAGE, MARKDOWN_TEXT,
TELEPHONE, TEXT, TEXT_OR_NUMBER, URL, URL_AUTHORITY);
}
public static Map<Type, List<Validation>> validationMap = new ImmutableMap.Builder<Type, List<Validation>>()
.put(Type.Assertion, List.of(
new Validation.Builder().name("id").type(ValueType.IRI).required(true).build(),
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(true).many(true).mustContainOneType(List.of(Type.Assertion)).build(),
new Validation.Builder().name("recipient").type(ValueType.ID).expectedType(Type.IdentityObject).required(true).build(),
new Validation.Builder().name("badge").type(ValueType.ID).prerequisite("ASN_FLATTEN_BC").expectedType(Type.BadgeClass).fetch(true).required(true).build(),
new Validation.Builder().name("verification").type(ValueType.ID).expectedTypes(List.of(Type.VerificationObjectAssertion)).required(true).build(),
new Validation.Builder().name("issuedOn").type(ValueType.DATETIME).required(true).build(),
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()
))
.put(Type.BadgeClass, List.of(
new Validation.Builder().name("id").type(ValueType.IRI).required(true).build(),
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(true).many(true).mustContainOneType(List.of(Type.BadgeClass)).build(),
new Validation.Builder().name("issuer").type(ValueType.ID).prerequisite("BC_FLATTEN_ISS").expectedType(Type.Profile).fetch(true).required(true).build(),
new Validation.Builder().name("name").type(ValueType.TEXT).required(true).build(),
new Validation.Builder().name("description").type(ValueType.TEXT).required(true).build(),
new Validation.Builder().name("image").type(ValueType.ID).required(false).allowRemoteUrl(true).expectedType(Type.Image).fetch(false).allowDataUri(true).build(),
new Validation.Builder().name("criteria").type(ValueType.ID).expectedType(Type.Criteria).fetch(false).required(true).allowRemoteUrl(true).build(),
new Validation.Builder().name("alignment").type(ValueType.ID).expectedType(Type.AlignmentObject).many(true).fetch(false).required(false).build(),
new Validation.Builder().name("tags").type(ValueType.TEXT).many(true).required(false).build()
))
.put(Type.AlignmentObject, List.of(
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).many(true).required(false).defaultType(Type.AlignmentObject).build(),
new Validation.Builder().name("targetName").type(ValueType.TEXT).required(true).build(),
new Validation.Builder().name("targetUrl").type(ValueType.URL).required(true).build(),
new Validation.Builder().name("description").type(ValueType.TEXT).required(false).build(),
new Validation.Builder().name("targetFramework").type(ValueType.TEXT).required(false).build(),
new Validation.Builder().name("targetCode").type(ValueType.TEXT).required(false).build()
))
.put(Type.Criteria, List.of(
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).many(true).required(false).defaultType(Type.Criteria).build(),
new Validation.Builder().name("id").type(ValueType.IRI).required(false).build(),
new Validation.Builder().name("narrative").type(ValueType.MARKDOWN_TEXT).required(false).build()
))
.put(Type.CryptographicKey, List.of(
new Validation.Builder().name("id").type(ValueType.IRI).required(false).build(),
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(false).many(true).defaultType(Type.CryptographicKey).build(),
new Validation.Builder().name("owner").type(ValueType.IRI).required(false).fetch(true).build(),
new Validation.Builder().name("publicKeyPem").type(ValueType.TEXT).required(false).build()
))
.put(Type.Endorsement, List.of(
new Validation.Builder().name("id").type(ValueType.IRI).required(true).build(),
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(true).many(true).mustContainOneType(List.of(Type.Endorsement)).build(),
new Validation.Builder().name("claim").type(ValueType.ID).required(true).allowRemoteUrl(false).fetch(false).allowDataUri(false).expectedTypes(List.of(Type.EndorsementClaim, Type.Endorsement)).fullValidate(false).build(),
new Validation.Builder().name("issuedOn").type(ValueType.DATETIME).required(true).build(),
new Validation.Builder().name("issuer").type(ValueType.ID).expectedType(Type.Profile).fetch(true).required(true).build(),
new Validation.Builder().name("verification").build()
))
.put(Type.EndorsementClaim, List.of(
new Validation.Builder().name("id").type(ValueType.IRI).required(true).build(),
new Validation.Builder().name("endorsementComment").type(ValueType.MARKDOWN_TEXT).required(false).build()
))
.put(Type.Evidence, List.of(
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).many(true).required(false).defaultType(Type.Evidence).build(),
new Validation.Builder().name("id").type(ValueType.IRI).required(false).build(),
new Validation.Builder().name("narrative").type(ValueType.MARKDOWN_TEXT).required(false).build(),
new Validation.Builder().name("name").type(ValueType.TEXT).required(false).build(),
new Validation.Builder().name("description").type(ValueType.TEXT).required(false).build(),
new Validation.Builder().name("genre").type(ValueType.TEXT).required(false).build(),
new Validation.Builder().name("audience").type(ValueType.TEXT).required(false).build()
))
.put(Type.ExpectedRecipientProfile, List.of(
new Validation.Builder().name("id").type(ValueType.IRI).required(false).build(),
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(false).many(true).mustContainOneType(List.of(Type.Issuer, Type.Profile)).defaultType(Type.Profile).build(),
new Validation.Builder().name("name").type(ValueType.TEXT).required(false).build(),
new Validation.Builder().name("description").type(ValueType.TEXT).required(false).build(),
new Validation.Builder().name("image").type(ValueType.ID).required(false).expectedType(Type.Image).fetch(false).allowDataUri(true).build(),
new Validation.Builder().name("url").type(ValueType.URL).required(false).many(true).build(),
new Validation.Builder().name("email").type(ValueType.EMAIL).required(false).many(true).build(),
new Validation.Builder().name("telephone").type(ValueType.TELEPHONE).required(false).many(true).build(),
new Validation.Builder().name("publicKey").type(ValueType.ID).many(true).expectedType(Type.CryptographicKey).fetch(false).required(false).build(),
new Validation.Builder().name("verification").type(ValueType.ID).expectedType(Type.VerificationObjectIssuer).fetch(false).required(false).build()
))
.put(Type.Extension, List.of())
.put(Type.IdentityObject, List.of(
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(true).many(false).mustContainOne(List.of("id", "email", "url", "telephone")).build(),
new Validation.Builder().name("identity").type(ValueType.IDENTITY_HASH).required(true).build(),
new Validation.Builder().name("hashed").type(ValueType.BOOLEAN).required(true).build(),
new Validation.Builder().name("salt").type(ValueType.TEXT).required(false).build()
))
.put(Type.Image, List.of(
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).many(true).required(false).defaultType("schema:ImageObject").build(),
new Validation.Builder().name("id").type(ValueType.DATA_URI_OR_URL).required(true).build(),
new Validation.Builder().name("caption").type(ValueType.TEXT).required(false).build(),
new Validation.Builder().name("author").type(ValueType.IRI).required(false).build()
))
.put(Type.Issuer, List.of(
new Validation.Builder().name("id").type(ValueType.IRI).required(true).build(),
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(true).many(true).mustContainOneType(List.of(Type.Issuer, Type.Profile)).build(),
new Validation.Builder().name("name").type(ValueType.TEXT).required(true).build(),
new Validation.Builder().name("description").type(ValueType.TEXT).required(false).build(),
new Validation.Builder().name("image").type(ValueType.ID).required(false).allowRemoteUrl(true).expectedType(Type.Image).fetch(false).allowDataUri(true).build(),
new Validation.Builder().name("url").type(ValueType.URL).required(true).build(),
new Validation.Builder().name("email").type(ValueType.EMAIL).required(true).build(),
new Validation.Builder().name("telephone").type(ValueType.TELEPHONE).required(false).build(),
new Validation.Builder().name("publicKey").type(ValueType.ID).expectedType(Type.CryptographicKey).fetch(true).required(false).build(),
new Validation.Builder().name("verification").type(ValueType.ID).expectedType(Type.VerificationObjectIssuer).fetch(false).required(false).build()
))
.put(Type.Profile, List.of(
new Validation.Builder().name("id").type(ValueType.IRI).required(true).build(),
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(true).many(true).mustContainOneType(List.of(Type.Issuer, Type.Profile)).build(),
new Validation.Builder().name("name").type(ValueType.TEXT).required(true).build(),
new Validation.Builder().name("description").type(ValueType.TEXT).required(false).build(),
new Validation.Builder().name("image").type(ValueType.ID).required(false).allowRemoteUrl(true).expectedType(Type.Image).fetch(false).allowDataUri(true).build(),
new Validation.Builder().name("url").type(ValueType.URL).required(true).build(),
new Validation.Builder().name("email").type(ValueType.EMAIL).required(true).build(),
new Validation.Builder().name("telephone").type(ValueType.TELEPHONE).required(false).build(),
new Validation.Builder().name("publicKey").type(ValueType.ID).expectedType(Type.CryptographicKey).fetch(true).required(false).build(),
new Validation.Builder().name("verification").type(ValueType.ID).expectedType(Type.VerificationObjectIssuer).fetch(false).required(false).build()
))
.put(Type.RevocationList, List.of(
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(true).many(true).mustContainOneType(List.of(Type.RevocationList)).build(),
new Validation.Builder().name("id").type(ValueType.IRI).required(false).build()
))
.put(Type.VerificationObject, List.of())
.put(Type.VerificationObjectAssertion, List.of(
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(true).many(false).mustContainOne(List.of("HostedBadge", "SignedBadge")).build(),
new Validation.Builder().name("creator").type(ValueType.ID).expectedType(Type.CryptographicKey).fetch(true).required(false).prerequisite("ASSERTION_VERIFICATION_DEPENDENCIES").build()
))
.put(Type.VerificationObjectIssuer, List.of(
new Validation.Builder().name("type").type(ValueType.RDF_TYPE).required(false).many(true).defaultType(Type.VerificationObject).build(),
new Validation.Builder().name("verificationProperty").type(ValueType.COMPACT_IRI).required(false).build(),
new Validation.Builder().name("startsWith").type(ValueType.URL).required(false).build(),
new Validation.Builder().name("allowedOrigins").type(ValueType.URL_AUTHORITY).required(false).many(true).build()
))
.build();
public static final String ID = Assertion.class.getCanonicalName(); public static final String ID = Assertion.class.getCanonicalName();
} }

View File

@ -0,0 +1,142 @@
package org.oneedtech.inspect.vc;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Validation class for Open Badges 2.0 types
*/
public class Validation {
private final String name;
private final Assertion.ValueType type;
private final boolean required;
private final boolean many;
private final List<String> mustContainOne;
private final List<String> prerequisites;
private final List<Assertion.Type> expectedTypes;
private final boolean allowRemoteUrl;
private final boolean allowDataUri;
private final boolean fetch;
private final String defaultType;
private final boolean fullValidate;
public Validation(Builder builder) {
this.name = builder.name;
this.type = builder.type;
this.required = builder.required;
this.many = builder.many;
this.mustContainOne = builder.mustContainOne;
this.prerequisites = builder.prerequisites;
this.expectedTypes = builder.expectedTypes;
this.allowRemoteUrl = builder.allowRemoteUrl;
this.allowDataUri = builder.allowDataUri;
this.fetch = builder.fetch;
this.defaultType = builder.defaultType;
this.fullValidate = builder.fullValidate;
}
public static class Builder {
private String name;
private Assertion.ValueType type;
private boolean required;
private boolean many;
private List<String> mustContainOne;
private List<String> prerequisites;
private List<Assertion.Type> expectedTypes;
private boolean allowRemoteUrl;
private boolean allowDataUri;
private boolean fetch;
private String defaultType;
private boolean fullValidate;
public Builder() {
this.mustContainOne = new ArrayList<>();
this.prerequisites = new ArrayList<>();
this.expectedTypes = new ArrayList<>();
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder type(Assertion.ValueType type) {
this.type = type;
return this;
}
public Builder required(boolean required) {
this.required = required;
return this;
}
public Builder many(boolean many) {
this.many = many;
return this;
}
public Builder mustContainOne(List<String> elems) {
this.mustContainOne = elems;
return this;
}
public Builder mustContainOneType(List<Assertion.Type> types) {
this.mustContainOne = types.stream().map(Assertion.Type::toString).collect(Collectors.toList());
return this;
}
public Builder prerequisites(List<String> elems) {
this.prerequisites = elems;
return this;
}
public Builder prerequisite(String elem) {
this.prerequisites = List.of(elem);
return this;
}
public Builder expectedTypes(List<Assertion.Type> elems) {
this.expectedTypes = elems;
return this;
}
public Builder expectedType(Assertion.Type type) {
this.expectedTypes = List.of(type);
return this;
}
public Builder allowRemoteUrl(boolean allowRemoteUrl) {
this.allowRemoteUrl = allowRemoteUrl;
return this;
}
public Builder allowDataUri(boolean allowDataUri) {
this.allowDataUri = allowDataUri;
return this;
}
public Builder fetch(boolean fetch) {
this.fetch = fetch;
return this;
}
public Builder defaultType(Assertion.Type defaultType) {
return defaultType(defaultType.toString());
}
public Builder defaultType(String defaultType) {
this.defaultType = defaultType;
return this;
}
public Builder fullValidate(boolean fullValidate) {
this.fullValidate = fullValidate;
return this;
}
public Validation build() {
return new Validation(this);
}
}
}