org.elastos.did.VerifiableCredential Maven / Gradle / Ivy
Show all versions of didsdk Show documentation
/*
* Copyright (c) 2019 Elastos Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.elastos.did;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.URI;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import org.elastos.did.backend.CredentialBiography;
import org.elastos.did.backend.CredentialTransaction;
import org.elastos.did.backend.IDChainRequest;
import org.elastos.did.exception.AlreadySealedException;
import org.elastos.did.exception.CredentialAlreadyExistException;
import org.elastos.did.exception.CredentialExpiredException;
import org.elastos.did.exception.CredentialNotGenuineException;
import org.elastos.did.exception.CredentialRevokedException;
import org.elastos.did.exception.DIDBackendException;
import org.elastos.did.exception.DIDException;
import org.elastos.did.exception.DIDNotFoundException;
import org.elastos.did.exception.DIDResolveException;
import org.elastos.did.exception.DIDStoreException;
import org.elastos.did.exception.DIDSyntaxException;
import org.elastos.did.exception.InvalidKeyException;
import org.elastos.did.exception.MalformedCredentialException;
import org.elastos.did.exception.MalformedDIDURLException;
import org.elastos.did.exception.NotAttachedWithStoreException;
import org.elastos.did.exception.UnknownInternalException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.PropertyFilter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
/**
* A verifiable credential can represent the information that a physical
* credential represents. The addition of technologies, such as digital
* signatures, makes verifiable credentials more tamper-evident and more
* trustworthy than their physical counterparts.
*
*
* This class following W3C's
* Verifiable Credentials Data Model 1.0
* specification.
*
*/
@JsonPropertyOrder({ VerifiableCredential.CONTEXT,
VerifiableCredential.ID,
VerifiableCredential.TYPE,
VerifiableCredential.ISSUER,
VerifiableCredential.ISSUANCE_DATE,
VerifiableCredential.EXPIRATION_DATE,
VerifiableCredential.CREDENTIAL_SUBJECT,
VerifiableCredential.PROOF })
@JsonFilter("credentialFilter")
public class VerifiableCredential extends DIDEntity implements DIDObject {
protected final static String CONTEXT = "@context";
protected final static String ID = "id";
protected final static String TYPE = "type";
protected final static String ISSUER = "issuer";
protected final static String ISSUANCE_DATE = "issuanceDate";
protected final static String EXPIRATION_DATE = "expirationDate";
protected final static String CREDENTIAL_SUBJECT = "credentialSubject";
protected final static String PROOF = "proof";
protected final static String VERIFICATION_METHOD = "verificationMethod";
protected final static String CREATED = "created";
protected final static String SIGNATURE = "signature";
/**
* W3C verifiable credential context URI.
*/
public final static String W3C_CREDENTIAL_CONTEXT = "https://www.w3.org/2018/credentials/v1";
/**
* Elastos verifiable credential context URI.
*/
public final static String ELASTOS_CREDENTIAL_CONTEXT = "https://ns.elastos.org/credentials/v1";
/**
* The default verifiable credential type.
*/
public final static String DEFAULT_CREDENTIAL_TYPE = "VerifiableCredential";
private static final Logger log = LoggerFactory.getLogger(VerifiableCredential.class);
@JsonProperty(CONTEXT)
@JsonInclude(Include.NON_EMPTY)
List context;
@JsonProperty(ID)
private DIDURL id;
@JsonProperty(TYPE)
@JsonFormat(with = {JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY})
private List type;
@JsonProperty(ISSUER)
private DID issuer;
@JsonProperty(ISSUANCE_DATE)
private Date issuanceDate;
@JsonProperty(EXPIRATION_DATE)
@JsonInclude(Include.NON_NULL)
private Date expirationDate;
@JsonProperty(CREDENTIAL_SUBJECT)
private Subject subject;
@JsonProperty(PROOF)
@JsonInclude(Include.NON_NULL)
private Proof proof;
private CredentialMetadata metadata;
/**
* The credential Subject object contains one or more properties that are
* each related to a credential owner.
*
* This id field is mandatory, should be the contoller's DID.
* All the other fields could be defined by the application.
* In order to support the JSON serialization, all values should be
* JSON serializable.
*/
@JsonPropertyOrder({ ID })
static public class Subject {
private DID id;
private TreeMap properties;
/**
* Constructs the credential Subject object with given controller.
*
* @param id the controller of this subject
*/
@JsonCreator
protected Subject(@JsonProperty(value = ID) DID id) {
this.id = id;
this.properties = new TreeMap();
}
/**
* Get the controller.
*
* @return the controller's DID object
*/
@JsonGetter(ID)
public DID getId() {
return id;
}
/**
* Set the controller of the Subject object.
*
* @param did the controller's DID
*/
void setId(DID did) {
this.id = did;
}
/**
* Helper getter method for properties serialization.
* NOTICE: Should keep the alphabetic serialization order.
*
* @return a String to Object map include all application defined
* properties
*/
@JsonAnyGetter
@JsonPropertyOrder(alphabetic = true)
private Map _getProperties() {
return properties;
}
/**
* Helper setter method for properties deserialization.
*
* @param name the property name
* @param value the property value
*/
@JsonAnySetter
private void setProperty(String name, Object value) {
if (name.equals(ID))
return;
properties.put(name, value);
}
/**
* Get the subject properties.
*
* @return the properties in String to Object map. It's a read-only map
*/
public Map getProperties() {
// TODO: make it unmodifiable recursively
return Collections.unmodifiableMap(properties);
}
/**
* Get the count of properties.
*
* @return the fields count
*/
public int getPropertyCount() {
return properties.size();
}
/**
* Get the specified property.
*
* @param name the property name
* @return the property value
*/
public Object getProperty(String name) {
return properties.get(name);
}
/**
* Get properties as a JSON string.
*
* @return the JSON string
*/
public String getPropertiesAsString() {
try {
return getObjectMapper().writeValueAsString(properties);
} catch (JsonProcessingException ignore) {
throw new UnknownInternalException(ignore);
}
}
}
/**
* The proof information for verifiable credential. The default proof
* type is ECDSAsecp256r1.
*/
@JsonPropertyOrder({ TYPE, CREATED, VERIFICATION_METHOD, SIGNATURE })
@JsonFilter("credentialProofFilter")
static public class Proof {
@JsonProperty(TYPE)
private String type;
@JsonProperty(CREATED)
@JsonInclude(Include.NON_NULL)
private Date created;
@JsonProperty(VERIFICATION_METHOD)
private DIDURL verificationMethod;
@JsonProperty(SIGNATURE)
private String signature;
/**
* Constructs a Proof object with the given values.
*
* @param type the verification method type
* @param method the verification method, normally it's a public key
* @param created the create date time stamp
* @param signature the signature encoded in base64 URL safe format
*/
@JsonCreator
protected Proof(@JsonProperty(value = TYPE) String type,
@JsonProperty(value = VERIFICATION_METHOD, required = true) DIDURL method,
@JsonProperty(value = CREATED) Date created,
@JsonProperty(value = SIGNATURE, required = true) String signature) {
this.type = type != null ? type : Constants.DEFAULT_PUBLICKEY_TYPE;
this.created = created == null ? null : new Date(created.getTime() / 1000 * 1000);
this.verificationMethod = method;
this.signature = signature;
}
/**
* Constructs a Proof object with the given values.
*
* @param method the verification method, normally it's a public key
* @param signature the signature encoded in base64 URL safe format
*/
protected Proof(DIDURL method, String signature) {
this(Constants.DEFAULT_PUBLICKEY_TYPE, method,
Calendar.getInstance(Constants.UTC).getTime(), signature);
}
/**
* Get the verification method type.
*
* @return the verification method type string
*/
public String getType() {
return type;
}
/**
* Get the verification method, normally it's a public key id.
*
* @return a verification method id
*/
public DIDURL getVerificationMethod() {
return verificationMethod;
}
/**
* Get the created time stamp.
*
* @return the created time stamp
*/
public Date getCreated() {
return created;
}
/**
* Get the signature.
*
* @return the signature encoded in URL safe base64 string
*/
public String getSignature() {
return signature;
}
static PropertyFilter getFilter() {
return new DIDPropertyFilter() {
@Override
protected boolean include(PropertyWriter writer, Object pojo, SerializeContext context) {
if (context.isNormalized())
return true;
Proof proof = (Proof)pojo;
switch (writer.getName()) {
case TYPE:
return !(proof.getType().equals(Constants.DEFAULT_PUBLICKEY_TYPE));
default:
return true;
}
}
};
}
}
/**
* Default constructor.
*/
protected VerifiableCredential() {
}
/**
* Copy constructor.
*
* @param vc the source credential object
*/
private VerifiableCredential(VerifiableCredential vc, boolean withProof) {
this.context = vc.context;
this.id = vc.id;
this.type = vc.type;
this.issuer = vc.issuer;
this.issuanceDate = vc.issuanceDate;
this.expirationDate = vc.expirationDate;
this.subject = vc.subject;
if (withProof)
this.proof = vc.proof;
}
private void checkAttachedStore() throws NotAttachedWithStoreException {
if (!getMetadata().attachedStore())
throw new NotAttachedWithStoreException();
}
/**
* Get the id of this credential object
*
* @return the id of this credential
*/
@Override
public DIDURL getId() {
return id;
}
/**
* Get the credential type.
*
* @return the type array
*/
@Override
public List getType() {
return Collections.unmodifiableList(type);
}
/**
* Get the issuer of this credential.
*
* @return the issuer's DID
*/
public DID getIssuer() {
return issuer;
}
/**
* Get the issuance time.
*
* @return the issuance time
*/
public Date getIssuanceDate() {
return issuanceDate;
}
/**
* Checks if there is an expiration time specified.
*
* @return whether the credential has expiration time
*/
protected boolean hasExpirationDate() {
return expirationDate != null;
}
/**
* Get the expire time.
*
* @return the expires time
*/
public Date getExpirationDate() {
if (expirationDate != null)
return expirationDate;
else {
try {
DIDDocument controllerDoc = subject.id.resolve();
if (controllerDoc != null)
return controllerDoc.getExpires();
} catch (DIDBackendException e) {
return null;
}
return null;
}
}
/**
* Get last modified time.
*
* @return the last modified time, maybe null for old version credential object
*/
public Date getLastModified() {
return proof.getCreated();
}
/**
* Get Credential subject object.
*
* @return the Credential Subject object
*/
public Subject getSubject() {
return subject;
}
/**
* Get Credential proof object.
*
* @return the Credential Proof object
*/
public Proof getProof() {
return proof;
}
/**
* Sanitize routine before sealing or after deserialization.
*
* @throws MalformedCredentialException if the credential object is invalid
*/
@Override
protected void sanitize() throws MalformedCredentialException {
if (id == null)
throw new MalformedCredentialException("Missing credential id");
if (type == null || type.isEmpty())
throw new MalformedCredentialException("Missing credential type");
if (issuanceDate == null)
throw new MalformedCredentialException("Missing credential issuance date");
if (expirationDate == null)
throw new MalformedCredentialException("Missing credential expiration date");
if (subject == null)
throw new MalformedCredentialException("Missing credential subject");
if (subject.id == null)
throw new MalformedCredentialException("Missing credential subject id");
if (proof == null)
throw new MalformedCredentialException("Missing credential proof");
Collections.sort(type);
// Update id references
if (issuer == null)
issuer = subject.id;
if (id.getDid() == null)
id.setDid(subject.id);
if (proof.verificationMethod.getDid() == null)
proof.verificationMethod.setDid(issuer);
}
/**
* Get current object's DID context.
*
* @return the DID object or null
*/
@Override
protected DID getSerializeContextDid() {
return getSubject().getId();
}
static PropertyFilter getFilter() {
return new DIDPropertyFilter() {
@Override
protected boolean include(PropertyWriter writer, Object pojo, SerializeContext context) {
if (context.isNormalized())
return true;
VerifiableCredential vc = (VerifiableCredential)pojo;
switch (writer.getName()) {
case ISSUER:
return !(vc.getIssuer().equals(context.getDid()));
default:
return true;
}
}
};
}
/**
* Set meta data for this credential object.
*
* @param metadata the metadata object
*/
protected void setMetadata(CredentialMetadata metadata) {
this.metadata = metadata;
this.getId().setMetadata(metadata);
}
/**
* Get the metadata object of this credential object.
*
* @return the Credential Meta data object
*/
public synchronized CredentialMetadata getMetadata() {
if (metadata == null) {
/*
// This will cause resolve recursively
try {
VerifiableCredential resolved = VerifiableCredential.resolve(getId(), getIssuer());
metadata = resolved != null ? resolved.getMetadata() : new CredentialMetadata(getId());
} catch (DIDResolveException e) {
metadata = new CredentialMetadata(getId());
}
*/
metadata = new CredentialMetadata(getId());
}
return metadata;
}
/**
* Whether the credential object has metadata attached.
*
* @return true if has metadata attached, false otherwise
*/
protected boolean hasMetadata() {
if (metadata == null)
return false;
if (metadata.isEmpty())
return false;
return true;
}
/**
* Get the attached DIDStore object.
*
* @return the DIDStore object if attached with store, null otherwise
*/
private DIDStore getStore() {
return metadata.getStore();
}
/**
* Check if this credential is a self proclaimed or not.
*
* @return whether the credential is self proclaimed
*/
public boolean isSelfProclaimed() {
return issuer.equals(subject.id);
}
/**
* Check if this credential object is expired or not.
*
* @return whether the credential object is expired
*/
public boolean isExpired() {
Calendar now = Calendar.getInstance(Constants.UTC);
Calendar expireDate = Calendar.getInstance(Constants.UTC);
expireDate.setTime(expirationDate);
return now.after(expireDate);
}
/**
* Check whether this credential object is genuine or not.
*
* @param listener the listener for the verification events and messages
* @return whether the credential object is genuine
* @throws DIDResolveException if error occurs when resolve the DIDs
*/
public boolean isGenuine(VerificationEventListener listener) throws DIDResolveException {
if (!getId().getDid().equals(getSubject().getId())) {
if (listener != null) {
listener.failed(this, "VC %s: invalid id '%s', should under the scope of '%s'",
getId(), getId(), getSubject().getId());
listener.failed(this, "VC %s: is not genuine", getId());
}
return false;
}
DIDDocument issuerDoc = issuer.resolve();
if (issuerDoc == null) {
//throw new DIDNotFoundException(issuer.toString());
if (listener != null) {
listener.failed(this, "VC %s: Can not resolve the document for issuer '%s'",
getId(), getIssuer());
listener.failed(this, "VC %s: is not genuine", getId());
}
return false;
}
if (!issuerDoc.isGenuine(listener)) {
if (listener != null) {
listener.failed(this, "VC %s: issuer '%s' is not genuine",
getId(), getIssuer());
listener.failed(this, "VC %s: is not genuine", getId());
}
return false;
}
// Credential should signed by any authentication key.
if (!issuerDoc.isAuthenticationKey(proof.getVerificationMethod())) {
if (listener != null) {
listener.failed(this, "VC %s: key '%s' for proof is not an authencation key of '%s'",
getId(), proof.getVerificationMethod(), proof.getVerificationMethod().getDid());
listener.failed(this, "VC %s: is not genuine", getId());
}
return false;
}
// Unsupported public key type;
if (!proof.getType().equals(Constants.DEFAULT_PUBLICKEY_TYPE)) {
if (listener != null) {
listener.failed(this, "VC %s: key type '%s' for proof is not supported",
getId(), proof.getType());
listener.failed(this, "VC %s: is not genuine", getId());
}
return false;
}
VerifiableCredential vc = new VerifiableCredential(this, false);
String json = vc.serialize(true);
if (!issuerDoc.verify(proof.getVerificationMethod(),
proof.getSignature(), json.getBytes())) {
if (listener != null) {
listener.failed(this, "VC %s: proof is invalid, signature mismatch", getId());
listener.failed(this, "VC %s: is not genuine", getId());
}
return false;
}
if (listener != null)
listener.succeeded(this, "VC %s: is genuine", getId());
return true;
}
// internal method for DIDDocument.Builder.addCredential,
// check the self-proclaimed credential that it's owner still not published
boolean isGenuineInternal(DIDDocument owner) {
checkState(isSelfProclaimed(), "The credential should be self-proclaimed");
checkArgument(getSubject().getId().equals(owner.getSubject()), "Invalid owner document");
if (!getId().getDid().equals(getSubject().getId()))
return false;
// Credential should signed by any authentication key.
if (!owner.isAuthenticationKey(proof.getVerificationMethod()))
return false;
// Unsupported public key type;
if (!proof.getType().equals(Constants.DEFAULT_PUBLICKEY_TYPE))
return false;
VerifiableCredential vc = new VerifiableCredential(this, false);
String json = vc.serialize(true);
if (!owner.verify(proof.getVerificationMethod(),
proof.getSignature(), json.getBytes()))
return false;
return true;
}
/**
* Check whether this credential object is genuine or not.
*
* @return whether the credential object is genuine
* @throws DIDResolveException if error occurs when resolve the DIDs
*/
public boolean isGenuine() throws DIDResolveException {
return isGenuine(null);
}
/**
* Check whether this credential object is genuine or not in asynchronous mode.
*
* @param listener the listener for the verification events and messages
* @return the new CompletableStage if success; null otherwise.
* The boolean result is genuine or not
*/
public CompletableFuture isGenuineAsync(VerificationEventListener listener) {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
return isGenuine(listener);
} catch (DIDResolveException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Check whether this credential object is genuine or not in asynchronous mode.
*
* @return the new CompletableStage if success; null otherwise.
* The boolean result is genuine or not
*/
public CompletableFuture isGenuineAsync() {
return isGenuineAsync(null);
}
/**
* Check whether this credential object is revoked or not.
*
* @return whether the credential object is revoked
* @throws DIDResolveException if error occurs when resolve the DIDs
*/
public boolean isRevoked() throws DIDResolveException {
if (getMetadata().isRevoked())
return true;
CredentialBiography bio = DIDBackend.getInstance().resolveCredentialBiography(
getId(), getIssuer());
if (bio == null)
return false;
boolean revoked = bio.getStatus() == CredentialBiography.Status.REVOKED;
if (revoked)
getMetadata().setRevoked(revoked);
return revoked;
}
/**
* Check whether this credential object is revoked or not in asynchronous mode.
*
* @return the new CompletableStage if success; null otherwise.
* The boolean result is revoked or not
*/
public CompletableFuture isRevokedAsync() {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
return isRevoked();
} catch (DIDResolveException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Check whether this credential object is valid or not.
*
* @param listener the listener for the verification events and messages
* @return whether the credential object is valid
* @throws DIDResolveException if error occurs when resolve the DIDs
*/
public boolean isValid(VerificationEventListener listener) throws DIDResolveException {
if (isRevoked()) {
if (listener != null) {
listener.failed(this, "%s: is revoked", getId());
listener.failed(this, "%s: is invalid", getId());
}
return false;
}
if (isExpired()) {
if (listener != null) {
listener.failed(this, "VC %s: is expired", getId());
listener.failed(this, "VC %s: is invalid", getId());
}
return false;
}
DIDDocument issuerDoc = issuer.resolve();
if (issuerDoc == null) {
//throw new DIDNotFoundException(issuer.toString());
if (listener != null) {
listener.failed(this, "VC %s: can not resolve the document for issuer '%s'",
getId(), getIssuer());
listener.failed(this, "VC %s: is invalid", getId());
}
return false;
}
if (issuerDoc.isDeactivated()) {
if (listener != null) {
listener.failed(this, "VC %s: issuer '%s' is invalid",
getId(), getIssuer());
listener.failed(this, "VC %s: is invalid", getId());
}
return false;
}
if (!issuerDoc.isGenuine(listener)) {
if (listener != null) {
listener.failed(this, "VC %s: issuer '%s' is not genuine",
getId(), getIssuer());
listener.failed(this, "VC %s: is invalid", getId());
}
return false;
}
// Credential should signed by any authentication key.
if (!issuerDoc.isAuthenticationKey(proof.getVerificationMethod())) {
if (listener != null) {
listener.failed(this, "VC %s: key '%s' for proof is not an authencation key of '%s'",
getId(), proof.getVerificationMethod(), proof.getVerificationMethod().getDid());
listener.failed(this, "VC %s: is invalid", this.getSubject());
}
return false;
}
// Unsupported public key type;
if (!proof.getType().equals(Constants.DEFAULT_PUBLICKEY_TYPE)){
if (listener != null) {
listener.failed(this, "VC %s: key type '%s' for proof is not supported",
getId(), proof.getType());
listener.failed(this, "VC %s: is invalid", getId());
}
return false;
}
VerifiableCredential vc = new VerifiableCredential(this, false);
String json = vc.serialize(true);
if (!issuerDoc.verify(proof.getVerificationMethod(),
proof.getSignature(), json.getBytes())){
if (listener != null) {
listener.failed(this, "VC %s: proof is invalid, signature mismatch", getId());
listener.failed(this, "VC %s: is invalid", getId());
}
return false;
}
if (listener != null)
listener.succeeded(this, "VC %s: is valid", getId());
return true;
}
/**
* Check whether this credential object is valid or not.
*
* @return whether the credential object is valid
* @throws DIDResolveException if error occurs when resolve the DIDs
*/
public boolean isValid() throws DIDResolveException {
return isValid(null);
}
/**
* Check whether this credential object is valid in asynchronous mode.
*
* @param listener the listener for the verification events and messages
* @return the new CompletableStage if success; null otherwise.
* The boolean result is valid or not
*/
public CompletableFuture isValidAsync(VerificationEventListener listener) {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
return isValid(listener);
} catch (DIDResolveException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Check whether this credential object is valid in asynchronous mode.
*
* @return the new CompletableStage if success; null otherwise.
* The boolean result is valid or not
*/
public CompletableFuture isValidAsync() {
return isValidAsync(null);
}
/**
* Check whether this credential object was declared or not.
*
* @return whether the credential object was declared
* @throws DIDResolveException if error occurs when resolve the DIDs
*/
public boolean wasDeclared() throws DIDResolveException {
CredentialBiography bio = DIDBackend.getInstance().resolveCredentialBiography(
getId(), getIssuer());
if (bio.getStatus() == CredentialBiography.Status.NOT_FOUND)
return false;
for (CredentialTransaction tx : bio.getAllTransactions()) {
if (tx.getRequest().getOperation() == IDChainRequest.Operation.DECLARE)
return true;
}
return false;
}
/**
* Check whether this credential object was declared in asynchronous mode.
*
* @return the new CompletableStage if success; null otherwise.
* The boolean result was declared or not
*/
public CompletableFuture wasDeclaredAsync() {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
return wasDeclared();
} catch (DIDResolveException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Publish this credential object to the ID chain, declare it to the public.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param signKey the contoller's key id to sign the declare transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void declare(DIDURL signKey, String storepass, DIDTransactionAdapter adapter)
throws DIDStoreException, DIDBackendException {
checkArgument(storepass != null && !storepass.isEmpty(), "Invalid storepass");
checkAttachedStore();
if (!isGenuine()) {
log.error("Publish failed because the credential is not genuine.");
throw new CredentialNotGenuineException(getId().toString());
}
if (isExpired()) {
log.error("Publish failed because the credential is expired.");
throw new CredentialExpiredException(getId().toString());
}
if (isRevoked()) {
log.error("Publish failed because the credential is revoked.");
throw new CredentialRevokedException(getId().toString());
}
if (wasDeclared()) {
log.error("Publish failed because the credential already declared.");
throw new CredentialAlreadyExistException(getId().toString());
}
DIDDocument owner = getStore().loadDid(getSubject().getId());
if (owner == null) {
// Fail-back: resolve the owner's document
owner = getSubject().getId().resolve();
if (owner == null)
throw new DIDNotFoundException(getSubject().getId().toString());
owner.getMetadata().attachStore(getStore());
}
if (signKey == null && owner.getDefaultPublicKeyId() == null)
throw new InvalidKeyException("Unknown sign key");
if (signKey != null) {
if (!owner.isAuthenticationKey(signKey))
throw new InvalidKeyException(signKey.toString());
} else {
signKey = owner.getDefaultPublicKeyId();
}
DIDBackend.getInstance().declareCredential(this, owner, signKey, storepass, adapter);
}
/**
* Publish this credential object to the ID chain, declare it to the public.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param signKey the contoller's key id to sign the declare transaction
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void declare(DIDURL signKey, String storepass)
throws DIDStoreException, DIDBackendException {
declare(signKey, storepass, null);
}
/**
* Publish this credential object to the ID chain, declare it to the public.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param signKey the contoller's key id to sign the declare transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void declare(String signKey, String storepass, DIDTransactionAdapter adapter)
throws DIDStoreException, DIDBackendException {
declare(DIDURL.valueOf(getSubject().getId(), signKey), storepass, adapter);
}
/**
* Publish this credential object to the ID chain, declare it to the public.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param signKey the contoller's key id to sign the declare transaction
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void declare(String signKey, String storepass)
throws DIDStoreException, DIDBackendException {
declare(DIDURL.valueOf(getSubject().getId(), signKey), storepass, null);
}
/**
* Publish this credential object to the ID chain, declare it to the public.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void declare(String storepass, DIDTransactionAdapter adapter)
throws DIDStoreException, DIDBackendException {
declare((DIDURL)null, storepass, adapter);
}
/**
* Publish this credential object to the ID chain, declare it to the public.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void declare(String storepass)
throws DIDStoreException, DIDBackendException {
declare((DIDURL)null, storepass, null);
}
/**
* Publish this credential object to the ID chain, declare it to the public
* in asynchronous mode.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param signKey the contoller's key id to sign the declare transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return a new CompletableStage
*/
public CompletableFuture declareAsync(DIDURL signKey, String storepass,
DIDTransactionAdapter adapter) {
CompletableFuture future = CompletableFuture.runAsync(() -> {
try {
declare(signKey, storepass, adapter);
} catch (DIDException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Publish this credential object to the ID chain, declare it to the public
* in asynchronous mode.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param signKey the contoller's key id to sign the declare transaction
* @param storepass the password of the DID store
* @return a new CompletableStage
*/
public CompletableFuture declareAsync(DIDURL signKey, String storepass) {
return declareAsync(signKey, storepass, null);
}
/**
* Publish this credential object to the ID chain, declare it to the public
* in asynchronous mode.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param signKey the contoller's key id to sign the declare transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return a new CompletableStage
*/
public CompletableFuture declareAsync(String signKey, String storepass,
DIDTransactionAdapter adapter) {
CompletableFuture future = CompletableFuture.runAsync(() -> {
try {
declare(signKey, storepass, adapter);
} catch (DIDException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Publish this credential object to the ID chain, declare it to the public
* in asynchronous mode.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param signKey the contoller's key id to sign the declare transaction
* @param storepass the password of the DID store
* @return a new CompletableStage
*/
public CompletableFuture declareAsync(String signKey, String storepass) {
return declareAsync(signKey, storepass, null);
}
/**
* Publish this credential object to the ID chain, declare it to the public
* in asynchronous mode.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return a new CompletableStage
*/
public CompletableFuture declareAsync(String storepass,
DIDTransactionAdapter adapter) {
return declareAsync((DIDURL)null, storepass, adapter);
}
/**
* Publish this credential object to the ID chain, declare it to the public
* in asynchronous mode.
*
*
* Only the owner of the credential object who can declare credential to
* public.
*
*
* @param storepass the password of the DID store
* @return a new CompletableStage
*/
public CompletableFuture declareAsync(String storepass) {
return declareAsync((DIDURL)null, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(DIDDocument signer, DIDURL signKey, String storepass,
DIDTransactionAdapter adapter) throws DIDStoreException, DIDBackendException {
checkArgument(storepass != null && !storepass.isEmpty(), "Invalid storepass");
// Prefer use the signer's store
if (signer != null && signer.getMetadata().attachedStore())
getMetadata().attachStore(signer.getStore());
checkAttachedStore();
DIDDocument owner = getSubject().getId().resolve();
if (owner == null) {
log.error("Publish failed because the credential owner is not published.");
throw new DIDNotFoundException(getSubject().getId().toString());
}
owner.getMetadata().attachStore(getStore());
DIDDocument issuer = getIssuer().resolve();
if (issuer == null) {
log.error("Publish failed because the credential issuer is not published.");
throw new DIDNotFoundException(getIssuer().toString());
}
issuer.getMetadata().attachStore(getStore());
if (isRevoked()) {
log.error("Publish failed because the credential is revoked.");
throw new CredentialRevokedException(getId().toString());
}
if (signer == null) {
DID signerDid = (signKey != null && signKey.getDid() != null) ?
signKey.getDid() : getSubject().getId();
signer = getStore().loadDid(signerDid);
if (signer == null) {
// Fail-back: resolve the owner's document
signer = getSubject().getId().resolve();
if (signer == null)
throw new DIDNotFoundException(getSubject().getId().toString());
signer.getMetadata().attachStore(getStore());
}
}
if (!signer.getSubject().equals(getSubject().getId()) &&
!signer.getSubject().equals(getIssuer()) &&
!owner.hasController(signer.getSubject()) &&
!issuer.hasController(signer.getSubject())) {
log.error("Publish failed because the invalid signer or signkey.");
throw new InvalidKeyException("Not owner or issuer: " + signer.getSubject());
}
if (signKey == null && signer.getDefaultPublicKeyId() == null)
throw new InvalidKeyException("Unknown sign key");
if (signKey != null) {
if (!signer.isAuthenticationKey(signKey))
throw new InvalidKeyException(signKey.toString());
} else {
signKey = signer.getDefaultPublicKeyId();
}
DIDBackend.getInstance().revokeCredential(this, signer, signKey, storepass, adapter);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(DIDDocument signer, DIDURL signKey, String storepass)
throws DIDStoreException, DIDBackendException {
revoke(signer, signKey, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(DIDDocument signer, String signKey, String storepass,
DIDTransactionAdapter adapter) throws DIDStoreException, DIDBackendException {
revoke(signer, DIDURL.valueOf(getSubject().getId(), signKey), storepass, adapter);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(DIDDocument signer, String signKey, String storepass)
throws DIDStoreException, DIDBackendException {
revoke(signer, signKey, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(DIDDocument signer, String storepass, DIDTransactionAdapter adapter)
throws DIDStoreException, DIDBackendException {
revoke(signer, (DIDURL)null, storepass, adapter);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(DIDDocument signer, String storepass)
throws DIDStoreException, DIDBackendException {
revoke(signer, (DIDURL)null, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(DIDURL signKey, String storepass, DIDTransactionAdapter adapter)
throws DIDStoreException, DIDBackendException {
revoke(null, signKey, storepass, adapter);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(DIDURL signKey, String storepass)
throws DIDStoreException, DIDBackendException {
revoke(null, signKey, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(String signKey, String storepass, DIDTransactionAdapter adapter)
throws DIDStoreException, DIDBackendException {
revoke(null, signKey, storepass, adapter);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(String signKey, String storepass)
throws DIDStoreException, DIDBackendException {
revoke(null, signKey, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(String storepass, DIDTransactionAdapter adapter)
throws DIDStoreException, DIDBackendException {
revoke(null, (DIDURL)null, storepass, adapter);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public void revoke(String storepass) throws DIDStoreException, DIDBackendException {
revoke(null, (DIDURL)null, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(DIDDocument signer,
DIDURL signKey, String storepass, DIDTransactionAdapter adapter) {
CompletableFuture future = CompletableFuture.runAsync(() -> {
try {
revoke(signer, signKey, storepass, adapter);
} catch (DIDException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(DIDDocument signer,
DIDURL signKey, String storepass) {
return revokeAsync(signer, signKey, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(DIDDocument signer,
String signKey, String storepass, DIDTransactionAdapter adapter) {
CompletableFuture future = CompletableFuture.runAsync(() -> {
try {
revoke(signer, signKey, storepass, adapter);
} catch (DIDException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(DIDDocument signer,
String signKey, String storepass) {
return revokeAsync(signer, signKey, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(DIDDocument signer,
String storepass, DIDTransactionAdapter adapter) {
return revokeAsync(signer, (DIDURL)null, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(DIDDocument signer,
String storepass) {
return revokeAsync(signer, (DIDURL)null, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(DIDURL signKey, String storepass,
DIDTransactionAdapter adapter) {
return revokeAsync(null, signKey, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(DIDURL signKey, String storepass) {
return revokeAsync(null, signKey, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(String signKey, String storepass,
DIDTransactionAdapter adapter) {
return revokeAsync(null, signKey, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(String signKey, String storepass) {
return revokeAsync(null, signKey, storepass, null);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(String storepass,
DIDTransactionAdapter adapter) {
return revokeAsync(null, (DIDURL)null, storepass, adapter);
}
/**
* Revoke this credential object and announce the revocation to the ID
* chain in asynchronous mode.
*
*
* The credential owner and issuer both can revoke the credential.
*
*
* @param storepass the password of the DID store
* @return a new CompletableStage
*/
public CompletableFuture revokeAsync(String storepass) {
return revokeAsync(null, (DIDURL)null, storepass, null);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public static void revoke(DIDURL id, DIDDocument signer, DIDURL signKey,
String storepass, DIDTransactionAdapter adapter)
throws DIDStoreException, DIDBackendException {
checkArgument(id != null, "Invalid credential id");
checkArgument(signer != null, "Invalid issuer's document");
checkArgument(storepass != null && !storepass.isEmpty(), "Invalid storepass");
if (!signer.getMetadata().attachedStore())
throw new NotAttachedWithStoreException(signer.getSubject().toString());
CredentialBiography bio = DIDBackend.getInstance().resolveCredentialBiography(id, signer.getSubject());
if (bio.getStatus() == CredentialBiography.Status.REVOKED) {
log.error("Publish failed because the credential is revoked.");
throw new CredentialRevokedException(id.toString());
}
if (bio.getStatus() == CredentialBiography.Status.VALID) {
VerifiableCredential vc = bio.getTransaction(0).getRequest().getCredential();
if (!signer.getSubject().equals(vc.getSubject().getId()) &&
!signer.getSubject().equals(vc.getIssuer())) {
log.error("Publish failed because the invalid signer or signkey.");
throw new InvalidKeyException("Not owner or issuer: " + signer.getSubject());
}
}
if (signKey == null && signer.getDefaultPublicKeyId() == null)
throw new InvalidKeyException("Unknown sign key");
if (signKey != null) {
if (!signer.isAuthenticationKey(signKey))
throw new InvalidKeyException(signKey.toString());
} else {
signKey = signer.getDefaultPublicKeyId();
}
DIDBackend.getInstance().revokeCredential(id, signer, signKey, storepass, adapter);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public static void revoke(DIDURL id, DIDDocument signer, DIDURL signKey, String storepass)
throws DIDStoreException, DIDBackendException {
revoke(id, signer, signKey, storepass, null);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public static void revoke(String id, DIDDocument signer, String signKey,
String storepass, DIDTransactionAdapter adapter)
throws DIDStoreException, DIDBackendException {
revoke(DIDURL.valueOf(id), signer, DIDURL.valueOf(signer.getSubject(), signKey),
storepass, adapter);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public static void revoke(String id, DIDDocument signer, String signKey, String storepass)
throws DIDStoreException, DIDBackendException {
revoke(DIDURL.valueOf(id), signer, DIDURL.valueOf(signer.getSubject(), signKey),
storepass, null);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public static void revoke(DIDURL id, DIDDocument signer, String storepass,
DIDTransactionAdapter adapter) throws DIDStoreException, DIDBackendException {
revoke(id, signer, null, storepass, adapter);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public static void revoke(DIDURL id, DIDDocument signer, String storepass)
throws DIDStoreException, DIDBackendException {
revoke(id, signer, null, storepass, null);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public static void revoke(String id, DIDDocument signer, String storepass,
DIDTransactionAdapter adapter) throws DIDStoreException, DIDBackendException {
revoke(DIDURL.valueOf(id), signer, null, storepass, adapter);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @throws DIDStoreException if an error occurred when accessing the DID store
* @throws DIDBackendException if an error occurred when publish the transaction
*/
public static void revoke(String id, DIDDocument signer, String storepass)
throws DIDStoreException, DIDBackendException {
revoke(DIDURL.valueOf(id), signer, null, storepass, null);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain
* in asynchronous mode.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return the new CompletableStage
*/
public static CompletableFuture revokeAsync(DIDURL id, DIDDocument signer,
DIDURL signKey, String storepass, DIDTransactionAdapter adapter) {
CompletableFuture future = CompletableFuture.runAsync(() -> {
try {
revoke(id, signer, signKey, storepass, adapter);
} catch (DIDException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Revoke a credential by id and announce the revocation to the ID chain
* in asynchronous mode.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @return the new CompletableStage
*/
public static CompletableFuture revokeAsync(DIDURL id,
DIDDocument signer, DIDURL signKey, String storepass) {
return revokeAsync(id, signer, signKey, storepass, null);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain
* in asynchronous mode.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return the new CompletableStage
*/
public static CompletableFuture revokeAsync(String id, DIDDocument signer,
String signKey, String storepass, DIDTransactionAdapter adapter) {
CompletableFuture future = CompletableFuture.runAsync(() -> {
try {
revoke(id, signer, signKey, storepass, adapter);
} catch (DIDException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Revoke a credential by id and announce the revocation to the ID chain
* in asynchronous mode.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param signKey the key id to sign the revoke transaction
* @param storepass the password of the DID store
* @return the new CompletableStage
*/
public static CompletableFuture revokeAsync(String id,
DIDDocument signer, String signKey, String storepass) {
return revokeAsync(id, signer, signKey, storepass, null);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain
* in asynchronous mode.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return the new CompletableStage
*/
public static CompletableFuture revokeAsync(DIDURL id, DIDDocument signer,
String storepass, DIDTransactionAdapter adapter) {
return revokeAsync(id, signer, null, storepass, adapter);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain
* in asynchronous mode.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @return the new CompletableStage
*/
public static CompletableFuture revokeAsync(DIDURL id,
DIDDocument signer, String storepass) {
return revokeAsync(id, signer, null, storepass, null);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain
* in asynchronous mode.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @param adapter an optional DIDTransactionAdapter object, use the
* DIDBackend's default implementation if null
* @return the new CompletableStage
*/
public static CompletableFuture revokeAsync(String id, DIDDocument signer,
String storepass, DIDTransactionAdapter adapter) {
return revokeAsync(id, signer, null, storepass, adapter);
}
/**
* Revoke a credential by id and announce the revocation to the ID chain
* in asynchronous mode.
*
* @param id the id of the credential to be revoke
* @param signer the DID document of credential owner or issuer
* @param storepass the password of the DID store
* @return the new CompletableStage
*/
public static CompletableFuture revokeAsync(String id,
DIDDocument signer, String storepass) {
return revokeAsync(id, signer, null, storepass, null);
}
/**
* Resolve the specific VerifiableCredential object.
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @param force if true then ignore the local cache and resolve the
* credential from the ID chain directly; otherwise will try
* to load the credential from the local cache, if the local
* cache not contains this credential, then resolve it from
* the ID chain
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static VerifiableCredential resolve(DIDURL id, DID issuer, boolean force)
throws DIDResolveException {
if (id == null)
throw new IllegalArgumentException();
VerifiableCredential vc = DIDBackend.getInstance().resolveCredential(
id, issuer, force);
if (vc != null)
id.setMetadata(vc.getMetadata());
return vc;
}
/**
* Resolve the specific VerifiableCredential object.
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @param force if true then ignore the local cache and resolve the
* credential from the ID chain directly; otherwise will try
* to load the credential from the local cache, if the local
* cache not contains this credential, then resolve it from
* the ID chain
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static VerifiableCredential resolve(String id, String issuer, boolean force)
throws DIDResolveException {
return resolve(DIDURL.valueOf(id), DID.valueOf(issuer), force);
}
/**
* Resolve the specific VerifiableCredential object.
*
*
* By default, this method will try to load the credential from the local
* cache, if the local cache not contains this credential, then try
* to resolve it from the ID chain.
*
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static VerifiableCredential resolve(DIDURL id, DID issuer)
throws DIDResolveException {
return resolve(id, issuer, false);
}
/**
* Resolve the specific VerifiableCredential object.
*
*
* By default, this method will try to load the credential from the local
* cache, if the local cache not contains this credential, then try
* to resolve it from the ID chain.
*
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static VerifiableCredential resolve(String id, String issuer)
throws DIDResolveException {
return resolve(DIDURL.valueOf(id), DID.valueOf(issuer), false);
}
/**
* Resolve the specific VerifiableCredential object.
*
* @param id the id of the target credential
* @param force if true then ignore the local cache and resolve the
* credential from the ID chain directly; otherwise will try
* to load the credential from the local cache, if the local
* cache not contains this credential, then resolve it from
* the ID chain
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static VerifiableCredential resolve(DIDURL id, boolean force)
throws DIDResolveException {
return resolve(id, null, force);
}
/**
* Resolve the specific VerifiableCredential object.
*
* @param id the id of the target credential
* @param force if true then ignore the local cache and resolve the
* credential from the ID chain directly; otherwise will try
* to load the credential from the local cache, if the local
* cache not contains this credential, then resolve it from
* the ID chain
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static VerifiableCredential resolve(String id, boolean force)
throws DIDResolveException {
return resolve(DIDURL.valueOf(id), null, force);
}
/**
* Resolve the specific VerifiableCredential object.
*
*
* By default, this method will try to load the credential from the local
* cache, if the local cache not contains this credential, then try
* to resolve it from the ID chain.
*
*
* @param id the id of the target credential
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static VerifiableCredential resolve(DIDURL id)
throws DIDResolveException {
return resolve(id, null, false);
}
/**
* Resolve the specific VerifiableCredential object.
*
*
* By default, this method will try to load the credential from the local
* cache, if the local cache not contains this credential, then try
* to resolve it from the ID chain.
*
*
* @param id the id of the target credential
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static VerifiableCredential resolve(String id)
throws DIDResolveException {
return resolve(DIDURL.valueOf(id), null, false);
}
/**
* Resolve the specific VerifiableCredential object in asynchronous mode.
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @param force if true then ignore the local cache and resolve the
* credential from the ID chain directly; otherwise will try
* to load the credential from the local cache, if the local
* cache not contains this credential, then resolve it from
* the ID chain
* @return a new CompletableStage, the result is the resolved
* VerifiableCredential object if success; null otherwise
*/
public static CompletableFuture resolveAsync(DIDURL id, DID issuer, boolean force) {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
return resolve(id, issuer, force);
} catch (DIDBackendException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Resolve the specific VerifiableCredential object in asynchronous mode.
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @param force if true then ignore the local cache and resolve the
* credential from the ID chain directly; otherwise will try
* to load the credential from the local cache, if the local
* cache not contains this credential, then resolve it from
* the ID chain
* @return a new CompletableStage, the result is the resolved
* VerifiableCredential object if success; null otherwise
*/
public static CompletableFuture resolveAsync(String id, String issuer, boolean force) {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
return resolve(id, issuer, force);
} catch (DIDBackendException | MalformedDIDURLException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Resolve the specific VerifiableCredential object in asynchronous mode.
*
*
* By default, this method will try to load the credential from the local
* cache, if the local cache not contains this credential, then try
* to resolve it from the ID chain.
*
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @return a new CompletableStage, the result is the resolved
* VerifiableCredential object if success; null otherwise
*/
public static CompletableFuture resolveAsync(DIDURL id, DID issuer) {
return resolveAsync(id, issuer, false);
}
/**
* Resolve the specific VerifiableCredential object in asynchronous mode.
*
*
* By default, this method will try to load the credential from the local
* cache, if the local cache not contains this credential, then try
* to resolve it from the ID chain.
*
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @return a new CompletableStage, the result is the resolved
* VerifiableCredential object if success; null otherwise
*/
public static CompletableFuture resolveAsync(String id, String issuer) {
return resolveAsync(id, issuer, false);
}
/**
* Resolve the specific VerifiableCredential object in asynchronous mode.
*
* @param id the id of the target credential
* @param force if true then ignore the local cache and resolve the
* credential from the ID chain directly; otherwise will try
* to load the credential from the local cache, if the local
* cache not contains this credential, then resolve it from
* the ID chain
* @return a new CompletableStage, the result is the resolved
* VerifiableCredential object if success; null otherwise
*/
public static CompletableFuture resolveAsync(DIDURL id, boolean force) {
return resolveAsync(id, null, force);
}
/**
* Resolve the specific VerifiableCredential object in asynchronous mode.
*
* @param id the id of the target credential
* @param force if true then ignore the local cache and resolve the
* credential from the ID chain directly; otherwise will try
* to load the credential from the local cache, if the local
* cache not contains this credential, then resolve it from
* the ID chain
* @return a new CompletableStage, the result is the resolved
* VerifiableCredential object if success; null otherwise
*/
public static CompletableFuture resolveAsync(String id, boolean force) {
return resolveAsync(id, null, force);
}
/**
* Resolve the specific VerifiableCredential object in asynchronous mode.
*
*
* By default, this method will try to load the credential from the local
* cache, if the local cache not contains this credential, then try
* to resolve it from the ID chain.
*
*
* @param id the id of the target credential
* @return a new CompletableStage, the result is the resolved
* VerifiableCredential object if success; null otherwise
*/
public static CompletableFuture resolveAsync(DIDURL id) {
return resolveAsync(id, null, false);
}
/**
* Resolve the specific VerifiableCredential object in asynchronous mode.
*
*
* By default, this method will try to load the credential from the local
* cache, if the local cache not contains this credential, then try
* to resolve it from the ID chain.
*
*
* @param id the id of the target credential
* @return a new CompletableStage, the result is the resolved
* VerifiableCredential object if success; null otherwise
*/
public static CompletableFuture resolveAsync(String id) {
return resolveAsync(id, null, false);
}
/**
* Resolve all transaction of the specific credential.
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static CredentialBiography resolveBiography(DIDURL id, DID issuer)
throws DIDResolveException {
checkArgument(id != null, "Invalid credential id");
return DIDBackend.getInstance().resolveCredentialBiography(id, issuer);
}
/**
* Resolve all transaction of the specific credential.
*
* @param id the id of the target credential
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static CredentialBiography resolveBiography(DIDURL id)
throws DIDResolveException {
checkArgument(id != null, "Invalid credential id");
return DIDBackend.getInstance().resolveCredentialBiography(id);
}
/**
* Resolve all transaction of the specific credential.
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static CredentialBiography resolveBiography(String id, String issuer)
throws DIDResolveException {
return resolveBiography(DIDURL.valueOf(id), DID.valueOf(issuer));
}
/**
* Resolve all transaction of the specific credential.
*
* @param id the id of the target credential
* @return the resolved VerifiableCredential object
* @throws DIDResolveException if an error occurred when resolving DID
*/
public static CredentialBiography resolveBiography(String id)
throws DIDResolveException {
return resolveBiography(id, null);
}
/**
* Resolve all transaction of the specific credential in asynchronous mode.
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @return a new CompletableStage, the result is the resolved
* CredentialBiography object if success; null otherwise
*/
public static CompletableFuture resolveBiographyAsync(DIDURL id, DID issuer) {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
return resolveBiography(id, issuer);
} catch (DIDResolveException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Resolve all transaction of the specific credential in asynchronous mode.
*
* @param id the id of the target credential
* @return a new CompletableStage, the result is the resolved
* CredentialBiography object if success; null otherwise
*/
public static CompletableFuture resolveBiographyAsync(DIDURL id) {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
return resolveBiography(id);
} catch (DIDResolveException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Resolve all transaction of the specific credential in asynchronous mode.
*
* @param id the id of the target credential
* @param issuer optional, the issuer's did
* @return a new CompletableStage, the result is the resolved
* CredentialBiography object if success; null otherwise
*/
public static CompletableFuture resolveBiographyAsync(String id, String issuer) {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
return resolveBiography(id, issuer);
} catch (DIDResolveException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* Resolve all transaction of the specific credential in asynchronous mode.
*
* @param id the id of the target credential
* @return a new CompletableStage, the result is the resolved
* CredentialBiography object if success; null otherwise
*/
public static CompletableFuture resolveBiographyAsync(String id) {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
return resolveBiography(id);
} catch (DIDResolveException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* List the published credentials that owned by the specific DID.
*
* @param did the did to be list
* @param skip set to skip N credentials ahead in this request
* (useful for pagination).
* @param limit set the limit of credentials returned in the request
* (useful for pagination).
* @return an array of DIDURL denoting the credentials
* @exception DIDResolveException if an error occurred when resolving the list
*/
public static List list(DID did, int skip, int limit)
throws DIDResolveException {
checkArgument(did != null, "Invalid did");
return DIDBackend.getInstance().listCredentials(did, skip, limit);
}
/**
* List the published credentials that owned by the specific DID.
*
* @param did the did to be list
* @param limit set the limit of credentials returned in the request
* (useful for pagination).
* @return an array of DIDURL denoting the credentials
* @exception DIDResolveException if an error occurred when resolving the list
*/
public static List list(DID did, int limit)
throws DIDResolveException {
checkArgument(did != null, "Invalid did");
return DIDBackend.getInstance().listCredentials(did, 0, limit);
}
/**
* List the published credentials that owned by the specific DID.
*
* @param did the did to be list
* @return an array of DIDURL denoting the credentials
* @exception DIDResolveException if an error occurred when resolving the list
*/
public static List list(DID did)
throws DIDResolveException {
checkArgument(did != null, "Invalid did");
return DIDBackend.getInstance().listCredentials(did, 0, 0);
}
/**
* List the published credentials that owned by the specific DID in
* asynchronous mode.
*
* @param did the did to be list
* @param skip set to skip N credentials ahead in this request
* (useful for pagination).
* @param limit set the limit of credentials returned in the request
* (useful for pagination).
* @return a new CompletableStage, the result is an array of DIDURL
* denoting the credentials
*/
public static CompletableFuture> listAsync(DID did, int skip, int limit) {
CompletableFuture> future = CompletableFuture.supplyAsync(() -> {
try {
return list(did, skip, limit);
} catch (DIDResolveException e) {
throw new CompletionException(e);
}
});
return future;
}
/**
* List the published credentials that owned by the specific DID in
* asynchronous mode.
*
* @param did the did to be list
* @param limit set the limit of credentials returned in the request
* (useful for pagination).
* @return a new CompletableStage, the result is an array of DIDURL
* denoting the credentials
*/
public static CompletableFuture> listAsync(DID did, int limit) {
return listAsync(did, 0, limit);
}
/**
* List the published credentials that owned by the specific DID in
* asynchronous mode.
*
* @param did the did to be list
* @return a new CompletableStage, the result is an array of DIDURL
* denoting the credentials
*/
public static CompletableFuture> listAsync(DID did) {
return listAsync(did, 0, 0);
}
/**
* Parse the VerifiableCredential object from a string JSON
* representation.
*
* @param content the string JSON content to deserialize the VerifiableCredential object
* @return the VerifiableCredential object
* @throws MalformedCredentialException if a parse error occurs
*/
public static VerifiableCredential parse(String content)
throws MalformedCredentialException {
try {
return parse(content, VerifiableCredential.class);
} catch (DIDSyntaxException e) {
if (e instanceof MalformedCredentialException)
throw (MalformedCredentialException)e;
else
throw new MalformedCredentialException(e);
}
}
/**
* Parse the VerifiableCredential object from a Reader object.
*
* @param src the Reader object to deserialize the VerifiableCredential object
* @return the VerifiableCredential object
* @throws MalformedCredentialException if a parse error occurs
* @throws IOException if an IO error occurs
*/
public static VerifiableCredential parse(Reader src)
throws MalformedCredentialException, IOException {
try {
return parse(src, VerifiableCredential.class);
} catch (DIDSyntaxException e) {
if (e instanceof MalformedCredentialException)
throw (MalformedCredentialException)e;
else
throw new MalformedCredentialException(e);
}
}
/**
* Parse the VerifiableCredential object from an input stream object.
*
* @param src the InputStream object to deserialize the VerifiableCredential object
* @return the VerifiableCredential object
* @throws MalformedCredentialException if a parse error occurs
* @throws IOException if an IO error occurs
*/
public static VerifiableCredential parse(InputStream src)
throws MalformedCredentialException, IOException {
try {
return parse(src, VerifiableCredential.class);
} catch (DIDSyntaxException e) {
if (e instanceof MalformedCredentialException)
throw (MalformedCredentialException)e;
else
throw new MalformedCredentialException(e);
}
}
/**
* Parse the VerifiableCredential object from a File object.
*
* @param src the File object to deserialize the VerifiableCredential object
* @return the VerifiableCredential object
* @throws MalformedCredentialException if a parse error occurs
* @throws IOException if an IO error occurs
*/
public static VerifiableCredential parse(File src)
throws MalformedCredentialException, IOException {
try {
return parse(src, VerifiableCredential.class);
} catch (DIDSyntaxException e) {
if (e instanceof MalformedCredentialException)
throw (MalformedCredentialException)e;
else
throw new MalformedCredentialException(e);
}
}
/**
* Parse the VerifiableCredential object from a string JSON
* representation.
*
* @param content the string representation of he credential object
* @return the VerifiableCredential object
* @throws MalformedCredentialException if a parse error occurs
* @deprecated use {@link #parse(String)} instead
*/
@Deprecated
public static VerifiableCredential fromJson(String content)
throws MalformedCredentialException {
return parse(content);
}
/**
* Parse the VerifiableCredential object from a reader object.
*
* @param src the Reader object to deserialize the credential object
* @return the VerifiableCredential object
* @throws MalformedCredentialException if a parse error occurs
* @throws IOException if an IO error occurs
* @deprecated use {@link #parse(Reader)} instead
*/
@Deprecated
public static VerifiableCredential fromJson(Reader src)
throws MalformedCredentialException, IOException {
return parse(src);
}
/**
* Parse the VerifiableCredential object from an input stream object.
*
* @param src the InputStream object to deserialize the credential object
* @return the VerifiableCredential object
* @throws MalformedCredentialException if a parse error occurs
* @throws IOException if an IO error occurs
* @deprecated use {@link #parse(InputStream)} instead
*/
@Deprecated
public static VerifiableCredential fromJson(InputStream src)
throws MalformedCredentialException, IOException {
return parse(src);
}
/**
* Parse the VerifiableCredential object from a File object.
*
* @param src the File object to deserialize the credential object
* @return the VerifiableCredential object
* @throws MalformedCredentialException if a parse error occurs
* @throws IOException if an IO error occurs
* @deprecated use {@link #parse(File)} instead
*/
@Deprecated
public static VerifiableCredential fromJson(File src)
throws MalformedCredentialException, IOException {
return parse(src);
}
/**
* The Builder object is a helper class to create a credential object.
*
* The credential object is immutable object. After set the contents for new
* credential, should call seal {@link Builder#seal(String)} method to
* create the final credential object.
*/
public static class Builder {
private Issuer issuer;
private DID target;
private VerifiableCredential credential;
/**
* Create a credential builder.
*
* @param issuer the credential issuer object
* @param target who the new credential issue to
*/
protected Builder(Issuer issuer, DID target) {
this.issuer = issuer;
this.target = target;
credential = new VerifiableCredential();
credential.issuer = issuer.getDid();
credential.subject = new Subject(target);
setDefaultType();
}
private void checkNotSealed() throws AlreadySealedException {
if (credential == null)
throw new AlreadySealedException();
}
/**
* Set the credential id.
*
* @param id the credential id
* @return the Builder instance for method chaining
*/
public Builder id(DIDURL id) {
checkNotSealed();
checkArgument(id != null && (id.getDid() == null || id.getDid().equals(target)),
"Invalid id");
if (id.getDid() == null)
id = new DIDURL(target, id);
credential.id = id;
return this;
}
/**
* Set the credential id.
*
* @param id the credential id
* @return the Builder instance for method chaining
*/
public Builder id(String id) {
return id(DIDURL.valueOf(target, id));
}
protected void setDefaultType() {
checkNotSealed();
if (Features.isEnabledJsonLdContext()) {
if (credential.context == null)
credential.context = new ArrayList();
if (!credential.context.contains(VerifiableCredential.W3C_CREDENTIAL_CONTEXT))
credential.context.add(VerifiableCredential.W3C_CREDENTIAL_CONTEXT);
if (!credential.context.contains(VerifiableCredential.ELASTOS_CREDENTIAL_CONTEXT))
credential.context.add(VerifiableCredential.ELASTOS_CREDENTIAL_CONTEXT);
}
if (credential.type == null)
credential.type = new ArrayList();
if (!credential.type.contains(DEFAULT_CREDENTIAL_TYPE))
credential.type.add(DEFAULT_CREDENTIAL_TYPE);
}
/**
* Add a new credential type.
*
* @param type the type name
* @param context the JSON-LD context for type, or null if not
* enabled the JSON-LD feature
* @return the Builder instance for method chaining
*/
public Builder type(String type, String context) {
checkNotSealed();
checkArgument(type != null && !type.isEmpty(), "Invalid type: " + String.valueOf(type));
if (Features.isEnabledJsonLdContext()) {
checkArgument(context != null && !context.isEmpty(), "Invalid context: " + String.valueOf(context));
if (credential.context == null)
credential.context = new ArrayList();
if (!credential.context.contains(context))
credential.context.add(context);
} else {
log.warn("JSON-LD context support not enabled, the context {} will be ignored", context);
}
if (credential.type == null)
credential.type = new ArrayList();
if (!credential.type.contains(type))
credential.type.add(type);
return this;
}
/**
* Add a new credential type.
*
* @param type the type name
* @param context the JSON-LD context for type, or null if not
* enabled the JSON-LD feature
* @return the Builder instance for method chaining
*/
public Builder type(String type, URI context) {
return type(type, context != null ? context.toString() : null);
}
/**
* Add a new credential type.
*
* If enabled the JSON-LD feature, the type should be a full type URI:
* [scheme:]scheme-specific-part#fragment,
* [scheme:]scheme-specific-part should be the context URL,
* the fragment should be the type name.
*
* Otherwise, the context URL part and # symbol could be omitted or
* ignored.
*
* @param type the type name
* @return the Builder instance for method chaining
*/
public Builder type(String type) {
checkNotSealed();
checkArgument(type != null && !type.isEmpty(), "Invalid type: " + String.valueOf(type));
if (type.indexOf('#') < 0)
return type(type, (String)null);
else {
String[] context_type = type.split("#", 2);
return type(context_type[1], context_type[0]);
}
}
/**
* Add a new credential type.
*
* If enabled the JSON-LD feature, the type should be a full type URI:
* [scheme:]scheme-specific-part#fragment,
* [scheme:]scheme-specific-part should be the context URL,
* the fragment should be the type name.
*
* Otherwise, the context URL part and # symbol could be omitted or
* ignored.
*
* @param type the type name
* @return the Builder instance for method chaining
*/
public Builder type(URI type) {
checkNotSealed();
checkArgument(type != null, "Invalid type: " + String.valueOf(type));
return type(type.toString());
}
/**
* Add new credential type.
*
* If enabled the JSON-LD feature, the type should be a full type URI:
* [scheme:]scheme-specific-part#fragment,
* [scheme:]scheme-specific-part should be the context URL,
* the fragment should be the type name.
*
* Otherwise, the context URL part and # symbol could be omitted or
* ignored.
*
* @param types the type names
* @return the Builder instance for method chaining
*/
public Builder types(String ... types) {
if (types == null || types.length == 0)
return this;
checkNotSealed();
for (String t : types)
type(t);
return this;
}
/**
* Add new credential types.
*
* If enabled the JSON-LD feature, the type should be a full type URI:
* [scheme:]scheme-specific-part#fragment,
* [scheme:]scheme-specific-part should be the context URL,
* the fragment should be the type name.
*
* Otherwise, the context URL part and # symbol could be omitted or
* ignored.
*
* @param types the type names
* @return the Builder instance for method chaining
*/
public Builder types(URI ... types) {
if (types == null || types.length == 0)
return this;
checkNotSealed();
for (URI t : types)
type(t);
return this;
}
private Calendar getMaxExpires() {
Calendar cal = Calendar.getInstance(Constants.UTC);
if (credential.getIssuanceDate() != null)
cal.setTime(credential.getIssuanceDate());
cal.add(Calendar.YEAR, Constants.MAX_VALID_YEARS);
return cal;
}
private Builder defaultExpirationDate() {
checkNotSealed();
credential.expirationDate = getMaxExpires().getTime();
return this;
}
/**
* Set expire time for the credential.
*
* @param expirationDate the expires time
* @return the Builder instance for method chaining
*/
public Builder expirationDate(Date expirationDate) {
checkNotSealed();
checkArgument(expirationDate != null, "Invalid expiration date");
Calendar cal = Calendar.getInstance(Constants.UTC);
cal.setTime(expirationDate);
Calendar maxExpires = getMaxExpires();
if (cal.after(maxExpires))
cal = maxExpires;
credential.expirationDate = cal.getTime();
return this;
}
/**
* Set the claim properties to the credential subject from a map object.
*
* @param properties a map object include the claims
* @return the Builder instance for method chaining
*/
public Builder properties(Map properties) {
checkNotSealed();
credential.subject.properties.clear();
if (properties == null || properties.size() == 0)
return this;
credential.subject.properties.putAll(properties);
credential.subject.properties.remove(ID);
return this;
}
/**
* Set the claim properties to the credential subject from JSON data.
*
* @param json the JSON string include the claims
* @return the Builder instance for method chaining
*/
public Builder properties(String json) {
checkNotSealed();
checkArgument(json != null && !json.isEmpty(), "Invalid json");
ObjectMapper mapper = getObjectMapper();
try {
Map props = mapper.readValue(json,
new TypeReference