Skip to content
This repository was archived by the owner on Mar 27, 2024. It is now read-only.

Commit 402bdce

Browse files
Merge branch 'main' into feature/add_sqlite_mobile_impl
2 parents ca7c46d + 1daefcc commit 402bdce

8 files changed

Lines changed: 1053 additions & 31 deletions

File tree

pkg/doc/cm/credentialmanifest.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,10 @@ type LabeledDisplayMappingObject struct {
106106
// Schema represents Type and (optional) Format information for a DisplayMappingObject that uses the Paths field,
107107
// as defined in https://identity.foundation/credential-manifest/wallet-rendering/#using-path.
108108
type Schema struct {
109-
Type string `json:"type,omitempty"` // MUST be here
110-
Format string `json:"format,omitempty"` // MAY be here if the Type is "string".
111-
ContentMediaType string `json:"mediatype,omitempty"` // MAY be here if the Type is "string".
112-
ContentEncoding string `json:"encoding,omitempty"` // MAY be here if the Type is "string".
109+
Type string `json:"type,omitempty"` // MUST be here
110+
Format string `json:"format,omitempty"` // MAY be here if the Type is "string".
111+
ContentMediaType string `json:"contentMediaType,omitempty"` // MAY be here if the Type is "string".
112+
ContentEncoding string `json:"contentEncoding,omitempty"` // MAY be here if the Type is "string".
113113
}
114114

115115
type staticDisplayMappingObjects struct {

pkg/doc/presexch/definition.go

Lines changed: 111 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
)
2828

2929
const (
30+
3031
// All rule`s value.
3132
All Selection = "all"
3233
// Pick rule`s value.
@@ -38,6 +39,8 @@ const (
3839
Preferred Preference = "preferred"
3940

4041
tmpEnding = "tmp_unique_id_"
42+
43+
credentialSchema = "credentialSchema"
4144
)
4245

4346
var errPathNotApplicable = errors.New("path not applicable")
@@ -93,6 +96,8 @@ type PresentationDefinition struct {
9396
// Format is an object with one or more properties matching the registered Claim Format Designations
9497
// (jwt, jwt_vc, jwt_vp, etc.) to inform the Holder of the claim format configurations the Verifier can process.
9598
Format *Format `json:"format,omitempty"`
99+
// Frame is used for JSON-LD document framing.
100+
Frame map[string]interface{} `json:"frame,omitempty"`
96101
// SubmissionRequirements must conform to the Submission Requirement Format.
97102
// If not present, all inputs listed in the InputDescriptors array are required for submission.
98103
SubmissionRequirements []*SubmissionRequirement `json:"submission_requirements,omitempty"`
@@ -121,6 +126,7 @@ type InputDescriptor struct {
121126
Metadata map[string]interface{} `json:"metadata,omitempty"`
122127
Schema []*Schema `json:"schema,omitempty"`
123128
Constraints *Constraints `json:"constraints,omitempty"`
129+
Format *Format `json:"format,omitempty"`
124130
}
125131

126132
// Schema input descriptor schema.
@@ -145,11 +151,12 @@ type Constraints struct {
145151

146152
// Field describes Constraints`s Fields field.
147153
type Field struct {
148-
Path []string `json:"path,omitempty"`
149-
ID string `json:"id,omitempty"`
150-
Purpose string `json:"purpose,omitempty"`
151-
Filter *Filter `json:"filter,omitempty"`
152-
Predicate *Preference `json:"predicate,omitempty"`
154+
Path []string `json:"path,omitempty"`
155+
ID string `json:"id,omitempty"`
156+
Purpose string `json:"purpose,omitempty"`
157+
Filter *Filter `json:"filter,omitempty"`
158+
Predicate *Preference `json:"predicate,omitempty"`
159+
IntentToRetain bool `json:"intent_to_retain,omitempty"`
153160
}
154161

155162
// Filter describes filter.
@@ -171,11 +178,21 @@ type Filter struct {
171178
// ValidateSchema validates presentation definition.
172179
func (pd *PresentationDefinition) ValidateSchema() error {
173180
result, err := gojsonschema.Validate(
174-
gojsonschema.NewStringLoader(DefinitionJSONSchema),
181+
gojsonschema.NewStringLoader(DefinitionJSONSchemaV1),
175182
gojsonschema.NewGoLoader(struct {
176183
PD *PresentationDefinition `json:"presentation_definition"`
177184
}{PD: pd}),
178185
)
186+
187+
if err != nil || !result.Valid() {
188+
result, err = gojsonschema.Validate(
189+
gojsonschema.NewStringLoader(DefinitionJSONSchemaV2),
190+
gojsonschema.NewGoLoader(struct {
191+
PD *PresentationDefinition `json:"presentation_definition"`
192+
}{PD: pd}),
193+
)
194+
}
195+
179196
if err != nil {
180197
return err
181198
}
@@ -310,7 +327,7 @@ func (pd *PresentationDefinition) CreateVP(credentials []*verifiable.Credential,
310327
return nil, err
311328
}
312329

313-
result, err := applyRequirement(req, credentials, documentLoader, opts...)
330+
result, err := pd.applyRequirement(req, credentials, documentLoader, opts...)
314331
if err != nil {
315332
return nil, err
316333
}
@@ -340,14 +357,33 @@ func (pd *PresentationDefinition) CreateVP(credentials []*verifiable.Credential,
340357
var ErrNoCredentials = errors.New("credentials do not satisfy requirements")
341358

342359
// nolint: gocyclo,funlen,gocognit
343-
func applyRequirement(req *requirement, creds []*verifiable.Credential,
360+
func (pd *PresentationDefinition) applyRequirement(req *requirement, creds []*verifiable.Credential,
344361
documentLoader ld.DocumentLoader, opts ...verifiable.CredentialOpt) (map[string][]*verifiable.Credential, error) {
345362
result := make(map[string][]*verifiable.Credential)
346363

347364
for _, descriptor := range req.InputDescriptors {
348-
filtered := filterSchema(descriptor.Schema, creds, documentLoader)
365+
format := pd.Format
366+
if descriptor.Format != nil {
367+
format = descriptor.Format
368+
}
369+
370+
filtered := creds
371+
372+
filtered, err := frameCreds(pd.Frame, filtered, opts...)
373+
if err != nil {
374+
return nil, err
375+
}
376+
377+
if format != nil {
378+
filtered = filterFormat(format, filtered)
379+
}
380+
381+
// Validate schema only for v1
382+
if descriptor.Schema != nil {
383+
filtered = filterSchema(descriptor.Schema, filtered, documentLoader)
384+
}
349385

350-
filtered, err := filterConstraints(descriptor.Constraints, filtered, opts...)
386+
filtered, err = filterConstraints(descriptor.Constraints, filtered, opts...)
351387
if err != nil {
352388
return nil, err
353389
}
@@ -371,7 +407,7 @@ func applyRequirement(req *requirement, creds []*verifiable.Credential,
371407
set := map[string]map[string]string{}
372408

373409
for _, r := range req.Nested {
374-
res, err := applyRequirement(r, creds, documentLoader, opts...)
410+
res, err := pd.applyRequirement(r, creds, documentLoader, opts...)
375411
if errors.Is(err, ErrNoCredentials) {
376412
continue
377413
}
@@ -594,10 +630,30 @@ func filterConstraints(constraints *Constraints, creds []*verifiable.Credential,
594630
return result, nil
595631
}
596632

633+
func frameCreds(frame map[string]interface{}, creds []*verifiable.Credential,
634+
opts ...verifiable.CredentialOpt) ([]*verifiable.Credential, error) {
635+
if frame == nil {
636+
return creds, nil
637+
}
638+
639+
var result []*verifiable.Credential
640+
641+
for _, credential := range creds {
642+
bbsVC, err := credential.GenerateBBSSelectiveDisclosure(frame, nil, opts...)
643+
if err != nil {
644+
return nil, err
645+
}
646+
647+
result = append(result, bbsVC)
648+
}
649+
650+
return result, nil
651+
}
652+
597653
func toSubject(subject interface{}) interface{} {
598654
sub, ok := subject.([]verifiable.Subject)
599655
if ok && len(sub) == 1 {
600-
return sub[0]
656+
return verifiable.Subject{ID: sub[0].ID}
601657
}
602658

603659
return subject
@@ -650,6 +706,10 @@ func createNewCredential(constraints *Constraints, src, limitedCred []byte,
650706
}
651707

652708
for _, path := range jPaths {
709+
if strings.Contains(path[0], credentialSchema) {
710+
continue
711+
}
712+
653713
var val interface{} = true
654714

655715
if !modifiedByPredicate {
@@ -772,26 +832,40 @@ func hasBBS(vc *verifiable.Credential) bool {
772832
return false
773833
}
774834

835+
func hasProofWithType(vc *verifiable.Credential, proofType string) bool {
836+
for _, proof := range vc.Proofs {
837+
if proof["type"] == proofType {
838+
return true
839+
}
840+
}
841+
842+
return false
843+
}
844+
775845
func filterField(f *Field, credential map[string]interface{}) error {
776846
var schema gojsonschema.JSONLoader
777847

778848
if f.Filter != nil {
779849
schema = gojsonschema.NewGoLoader(*f.Filter)
780850
}
781851

852+
var lastErr error
853+
782854
for _, path := range f.Path {
783855
patch, err := jsonpath.Get(path, credential)
784-
if err != nil {
785-
return errPathNotApplicable
786-
}
856+
if err == nil {
857+
err = validatePatch(schema, patch)
858+
if err == nil {
859+
return nil
860+
}
787861

788-
err = validatePatch(schema, patch)
789-
if err != nil {
790-
return err
862+
lastErr = err
863+
} else {
864+
lastErr = errPathNotApplicable
791865
}
792866
}
793867

794-
return nil
868+
return lastErr
795869
}
796870

797871
func validatePatch(schema gojsonschema.JSONLoader, patch interface{}) error {
@@ -888,6 +962,24 @@ func (a byID) Len() int { return len(a) }
888962
func (a byID) Less(i, j int) bool { return a[i].ID < a[j].ID }
889963
func (a byID) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
890964

965+
func filterFormat(format *Format, credentials []*verifiable.Credential) []*verifiable.Credential {
966+
var result []*verifiable.Credential
967+
968+
if format.LdpVP == nil {
969+
return result
970+
}
971+
972+
for _, credential := range credentials {
973+
for _, proofType := range format.LdpVP.ProofType {
974+
if hasProofWithType(credential, proofType) {
975+
result = append(result, credential)
976+
}
977+
}
978+
}
979+
980+
return result
981+
}
982+
891983
// nolint: gocyclo
892984
func filterSchema(schemas []*Schema, credentials []*verifiable.Credential,
893985
documentLoader ld.DocumentLoader) []*verifiable.Credential {

pkg/doc/presexch/definition_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,9 @@ func TestPresentationDefinition_CreateVP(t *testing.T) {
10321032
Constraints: &Constraints{
10331033
SubjectIsIssuer: &subIsIssuerRequired,
10341034
Fields: []*Field{{
1035-
Path: []string{"$.first_name", "$.last_name"},
1035+
Path: []string{"$.first_name"},
1036+
}, {
1037+
Path: []string{"$.last_name"},
10361038
}},
10371039
},
10381040
}, {
@@ -1042,7 +1044,9 @@ func TestPresentationDefinition_CreateVP(t *testing.T) {
10421044
}},
10431045
Constraints: &Constraints{
10441046
Fields: []*Field{{
1045-
Path: []string{"$.first_name", "$.last_name"},
1047+
Path: []string{"$.first_name"},
1048+
}, {
1049+
Path: []string{"$.last_name"},
10461050
}},
10471051
},
10481052
}},
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222

2323
const dummy = "DUMMY"
2424

25-
func ExamplePresentationDefinition_CreateVP() {
25+
func ExamplePresentationDefinition_CreateVP_v1() {
2626
required := Required
2727

2828
pd := &PresentationDefinition{

0 commit comments

Comments
 (0)