Skip to content

Commit 38b8760

Browse files
authored
Merge pull request #59 from danubetech/fix/v2-issues
V2 presentation issues
2 parents b42f22e + c78fe8d commit 38b8760

File tree

7 files changed

+150
-9
lines changed

7 files changed

+150
-9
lines changed

src/main/java/com/danubetech/verifiablecredentials/VerifiableCredentialV2.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public static class Builder<B extends Builder<B>> extends JsonLDObject.Builder<B
4242
private Object issuer;
4343
private Date validFrom;
4444
private Date validUntil;
45-
private CredentialSubject credentialSubject;
45+
private List<CredentialSubject> credentialSubject;
4646
private List<CredentialStatus> credentialStatus;
4747
private String name;
4848
private String description;
@@ -72,7 +72,7 @@ public VerifiableCredentialV2 build() {
7272
if (this.issuer != null) JsonLDUtils.jsonLdAdd(this.jsonLdObject, VerifiableCredentialKeywords.JSONLD_TERM_ISSUER, this.issuer instanceof URI ? JsonLDUtils.uriToString((URI) this.issuer) : this.issuer);
7373
if (this.validFrom != null) JsonLDUtils.jsonLdAdd(this.jsonLdObject, VerifiableCredentialKeywords.JSONLD_TERM_VALIDFROM, JsonLDUtils.dateToString(this.validFrom));
7474
if (this.validUntil != null) JsonLDUtils.jsonLdAdd(this.jsonLdObject, VerifiableCredentialKeywords.JSONLD_TERM_VALIDUNTIL, JsonLDUtils.dateToString(this.validUntil));
75-
if (this.credentialSubject != null) this.credentialSubject.addToJsonLDObject(this.jsonLdObject);
75+
if (this.credentialSubject != null) this.credentialSubject.forEach(credentialSubject -> credentialSubject.addToJsonLDObject(this.jsonLdObject));
7676
if (this.credentialStatus != null) this.credentialStatus.forEach(credentialStatus -> credentialStatus.addToJsonLDObject(this.jsonLdObject));
7777
if (this.name != null) JsonLDUtils.jsonLdAdd(this.jsonLdObject, VerifiableCredentialKeywords.JSONLD_TERM_NAME, this.name);
7878
if (this.description != null) JsonLDUtils.jsonLdAdd(this.jsonLdObject, VerifiableCredentialKeywords.JSONLD_TERM_NAME, this.description);
@@ -108,7 +108,8 @@ public B validUntil(Date validUntil) {
108108
}
109109

110110
public B credentialSubject(CredentialSubject credentialSubject) {
111-
this.credentialSubject = credentialSubject;
111+
if(this.credentialSubject == null) this.credentialSubject = new ArrayList<>();
112+
this.credentialSubject.add(credentialSubject);
112113
return (B) this;
113114
}
114115

@@ -258,6 +259,10 @@ public CredentialSubject getCredentialSubject() {
258259
return CredentialSubject.getFromJsonLDObject(this);
259260
}
260261

262+
public List<CredentialSubject> getCredentialSubjectAsList() {
263+
return CredentialSubject.getFromJsonLDObjectAsList(this);
264+
}
265+
261266
public CredentialStatus getCredentialStatus() {
262267
return CredentialStatus.getFromJsonLDObject(this);
263268
}

src/main/java/com/danubetech/verifiablecredentials/VerifiablePresentation.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,16 @@ public String getJwtVerifiableCredentialString() {
156156
throw new IllegalArgumentException("Cannot get JWT verifiable credential: " + verifiableCredentialObject);
157157
}
158158

159+
public List<String> getJwtVerifiableCredentialStringAsList() {
160+
Object verifiableCredentialObject = this.getJsonObject().get(VerifiableCredentialKeywords.JSONLD_TERM_VERIFIABLECREDENTIAL);
161+
if (verifiableCredentialObject instanceof List<?> && ! ((List<?>) verifiableCredentialObject).isEmpty() && ((List<?>) verifiableCredentialObject).get(0) instanceof String) {
162+
return (List<String>) verifiableCredentialObject;
163+
} else if (verifiableCredentialObject instanceof String) {
164+
return List.of((String) verifiableCredentialObject);
165+
}
166+
throw new IllegalArgumentException("Cannot get JWT verifiable credential: " + verifiableCredentialObject);
167+
}
168+
159169
public DataIntegrityProof getDataIntegrityProof() {
160170
return DataIntegrityProof.getFromJsonLDObject(this);
161171
}

src/main/java/com/danubetech/verifiablecredentials/VerifiablePresentationV2.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,16 @@ public String getJwtVerifiableCredentialString() {
156156
return null;
157157
}
158158

159+
public List<String> getJwtVerifiableCredentialStringAsList() {
160+
Object verifiableCredentialObject = this.getJsonObject().get(VerifiableCredentialKeywords.JSONLD_TERM_VERIFIABLECREDENTIAL);
161+
if (verifiableCredentialObject instanceof List<?> && ! ((List<?>) verifiableCredentialObject).isEmpty() && ((List<?>) verifiableCredentialObject).get(0) instanceof String) {
162+
return (List<String>) verifiableCredentialObject;
163+
} else if (verifiableCredentialObject instanceof String) {
164+
return List.of((String) verifiableCredentialObject);
165+
}
166+
throw new IllegalArgumentException("Cannot get JWT verifiable credential: " + verifiableCredentialObject);
167+
}
168+
159169
public DataIntegrityProof getDataIntegrityProof() {
160170
return DataIntegrityProof.getFromJsonLDObject(this);
161171
}

src/main/java/com/danubetech/verifiablecredentials/jwt/FromJwtConverter.java

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.danubetech.verifiablecredentials.VerifiableCredential;
55
import com.danubetech.verifiablecredentials.VerifiableCredentialV2;
66
import com.danubetech.verifiablecredentials.VerifiablePresentation;
7+
import com.danubetech.verifiablecredentials.VerifiablePresentationV2;
78
import com.danubetech.verifiablecredentials.jsonld.VerifiableCredentialKeywords;
89
import com.nimbusds.jwt.JWTClaimsSet;
910
import foundation.identity.jsonld.JsonLDUtils;
@@ -66,9 +67,7 @@ public static VerifiableCredential fromJwtVerifiableCredential(JwtVerifiableCred
6667
verifiableCredentialBuilder.expirationDate(expirationTime);
6768
}
6869

69-
VerifiableCredential verifiableCredential = verifiableCredentialBuilder.build();
70-
71-
return verifiableCredential;
70+
return verifiableCredentialBuilder.build();
7271
}
7372

7473
public static VerifiablePresentation fromJwtVerifiablePresentation(JwtVerifiablePresentation jwtVerifiablePresentation) {
@@ -92,9 +91,7 @@ public static VerifiablePresentation fromJwtVerifiablePresentation(JwtVerifiable
9291
verifiablePresentationBuilder.holder(URI.create(issuer));
9392
}
9493

95-
VerifiablePresentation verifiablePresentation = verifiablePresentationBuilder.build();
96-
97-
return verifiablePresentation;
94+
return verifiablePresentationBuilder.build();
9895
}
9996

10097
public static VerifiablePresentation fromJwtVerifiableCredentialToVerifiablePresentation(JwtVerifiableCredential jwtVerifiableCredential) {
@@ -160,4 +157,29 @@ public static VerifiableCredentialV2 fromJwtVerifiableCredentialV2(JwtVerifiable
160157

161158
return verifiableCredentialBuilder.build();
162159
}
160+
161+
public static VerifiablePresentationV2 fromJwtVerifiablePresentationV2(JwtVerifiablePresentationV2 jwtVerifiablePresentation) {
162+
163+
VerifiablePresentationV2 payloadVerifiablePresentation = VerifiablePresentationV2.fromJson(jwtVerifiablePresentation.getPayloadObject().toString());
164+
165+
VerifiablePresentationV2.Builder<? extends VerifiablePresentationV2.Builder<?>> verifiablePresentationBuilder = VerifiablePresentationV2.builder()
166+
.base(payloadVerifiablePresentation)
167+
.defaultContexts(false)
168+
.defaultTypes(false);
169+
170+
JWTClaimsSet payload = jwtVerifiablePresentation.getPayload();
171+
172+
String jwtId = payload.getJWTID();
173+
if (jwtId != null && payloadVerifiablePresentation.getId() == null) {
174+
verifiablePresentationBuilder.id(URI.create(jwtId));
175+
}
176+
177+
String issuer = payload.getIssuer();
178+
if (issuer != null && payloadVerifiablePresentation.getHolder() == null) {
179+
verifiablePresentationBuilder.holder(URI.create(issuer));
180+
}
181+
182+
return verifiablePresentationBuilder.build();
183+
}
184+
163185
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.danubetech.verifiablecredentials.jwt;
2+
3+
import com.danubetech.verifiablecredentials.VerifiablePresentation;
4+
import com.danubetech.verifiablecredentials.VerifiablePresentationV2;
5+
import com.nimbusds.jose.JWSObject;
6+
import com.nimbusds.jwt.JWTClaimsSet;
7+
import com.nimbusds.jwt.SignedJWT;
8+
9+
import java.text.ParseException;
10+
import java.util.LinkedHashMap;
11+
import java.util.Map;
12+
13+
public class JwtVerifiablePresentationV2 extends JwtWrappingObject<VerifiablePresentationV2> {
14+
15+
public JwtVerifiablePresentationV2(JWTClaimsSet payload, VerifiablePresentationV2 payloadObject, JWSObject jwsObject, String compactSerialization) {
16+
17+
super(payload, payloadObject, jwsObject, compactSerialization);
18+
}
19+
20+
/*
21+
* Factory methods
22+
*/
23+
24+
public static JwtVerifiablePresentationV2 fromCompactSerialization(String compactSerialization) throws ParseException {
25+
26+
SignedJWT signedJWT = SignedJWT.parse(compactSerialization);
27+
28+
JWTClaimsSet jwtPayload = signedJWT.getJWTClaimsSet();
29+
Map<String, Object> jsonObject = (Map<String, Object>) jwtPayload.getClaims().get(JwtKeywords.JWT_CLAIM_VP);
30+
if (jsonObject == null) return null;
31+
32+
VerifiablePresentationV2 payloadVerifiablePresentation = VerifiablePresentationV2.fromJsonObject(new LinkedHashMap<>(jsonObject));
33+
34+
return new JwtVerifiablePresentationV2(jwtPayload, payloadVerifiablePresentation, signedJWT, compactSerialization);
35+
}
36+
}

src/main/java/com/danubetech/verifiablecredentials/jwt/ToJwtConverter.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.danubetech.verifiablecredentials.VerifiableCredential;
55
import com.danubetech.verifiablecredentials.VerifiableCredentialV2;
66
import com.danubetech.verifiablecredentials.VerifiablePresentation;
7+
import com.danubetech.verifiablecredentials.VerifiablePresentationV2;
78
import com.danubetech.verifiablecredentials.jsonld.VerifiableCredentialKeywords;
89
import com.nimbusds.jwt.JWTClaimsSet;
910
import foundation.identity.jsonld.JsonLDKeywords;
@@ -237,4 +238,45 @@ public static JwtVerifiableCredentialV2 toJwtVerifiableCredentialV2(VerifiableCr
237238

238239
return toJwtVerifiableCredentialV2(verifiableCredential, null, false, false);
239240
}
241+
242+
public static JwtVerifiablePresentationV2 toJwtVerifiablePresentation(VerifiablePresentationV2 verifiablePresentation, String aud) {
243+
244+
JWTClaimsSet.Builder jwtPayloadBuilder = new JWTClaimsSet.Builder();
245+
246+
VerifiablePresentationV2 payloadVerifiablePresentation = VerifiablePresentationV2.builder()
247+
.defaultContexts(false)
248+
.defaultTypes(false)
249+
.build();
250+
251+
JsonLDUtils.jsonLdAddAll(payloadVerifiablePresentation, verifiablePresentation.getJsonObject());
252+
253+
URI id = verifiablePresentation.getId();
254+
if (id != null) {
255+
jwtPayloadBuilder.jwtID(id.toString());
256+
JsonLDUtils.jsonLdRemove(payloadVerifiablePresentation, JsonLDKeywords.JSONLD_TERM_ID);
257+
}
258+
259+
URI holder = verifiablePresentation.getHolder();
260+
if (holder != null) {
261+
jwtPayloadBuilder.issuer(holder.toString());
262+
jwtPayloadBuilder.subject(holder.toString());
263+
JsonLDUtils.jsonLdRemove(payloadVerifiablePresentation, VerifiableCredentialKeywords.JSONLD_TERM_HOLDER);
264+
}
265+
266+
if (aud != null) {
267+
jwtPayloadBuilder.audience(aud);
268+
}
269+
270+
Map<String, Object> vpContent = new LinkedHashMap<>(payloadVerifiablePresentation.getJsonObject());
271+
jwtPayloadBuilder.claim(JwtKeywords.JWT_CLAIM_VP, vpContent);
272+
273+
JWTClaimsSet jwtPayload = jwtPayloadBuilder.build();
274+
275+
return new JwtVerifiablePresentationV2(jwtPayload, payloadVerifiablePresentation, null, null);
276+
}
277+
278+
public static JwtVerifiablePresentationV2 toJwtVerifiablePresentation(VerifiablePresentationV2 verifiablePresentation) {
279+
280+
return toJwtVerifiablePresentation(verifiablePresentation, null);
281+
}
240282
}

src/main/java/com/danubetech/verifiablecredentials/validation/Validation.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.danubetech.verifiablecredentials.VerifiableCredential;
44
import com.danubetech.verifiablecredentials.VerifiableCredentialV2;
55
import com.danubetech.verifiablecredentials.VerifiablePresentation;
6+
import com.danubetech.verifiablecredentials.VerifiablePresentationV2;
67
import com.danubetech.verifiablecredentials.credentialstatus.CredentialStatus;
78

89
import java.net.URI;
@@ -118,6 +119,21 @@ public static void validate(VerifiableCredentialV2 verifiableCredential) throws
118119
validateStatus(verifiableCredential);
119120
}
120121

122+
public static void validate(VerifiablePresentationV2 verifiablePresentation) throws IllegalStateException {
123+
124+
foundation.identity.jsonld.validation.Validation.validate(verifiablePresentation);
125+
126+
validateRun(() -> validateTrue(verifiablePresentation.getJsonObject() != null), "Bad or missing JSON object.");
127+
validateRun(() -> validateTrue(! verifiablePresentation.getContexts().isEmpty()), "Bad or missing '@context'.");
128+
validateRun(() -> validateUrl(verifiablePresentation.getContexts().get(0)), "@context must be a valid URI: " + verifiablePresentation.getContexts().get(0));
129+
validateRun(() -> validateTrue(VerifiableCredentialV2.DEFAULT_JSONLD_CONTEXTS[0].equals(verifiablePresentation.getContexts().get(0))), "First value of @context must be " + VerifiableCredentialV2.DEFAULT_JSONLD_CONTEXTS[0] + ": " + verifiablePresentation.getContexts().get(0));
130+
validateRun(() -> { if (verifiablePresentation.getId() != null) validateUrl(verifiablePresentation.getId()); }, "'id' must be a valid URI.");
131+
132+
validateRun(() -> validateTrue(! verifiablePresentation.getTypes().isEmpty()), "Bad or missing 'type'.");
133+
validateRun(() -> validateTrue(verifiablePresentation.getTypes().contains(VerifiablePresentationV2.DEFAULT_JSONLD_TYPES[0])), "type must contain VerifiablePresentation: " + verifiablePresentation.getTypes());
134+
validateOneOfRuns(List.of(() -> validateTrue(verifiablePresentation.getVerifiableCredentialAsList() != null), () -> validateTrue(verifiablePresentation.getJwtVerifiableCredentialString() != null)), "Bad or missing 'verifiableCredential'.");
135+
}
136+
121137
private static void validateIssuer(VerifiableCredentialV2 verifiableCredential) throws IllegalStateException {
122138

123139
validateRun(() -> validateTrue(verifiableCredential.getIssuer() != null), "Bad or missing 'issuer'.");

0 commit comments

Comments
 (0)