From 6560f980318605ae7457fe5b212fbf260b3d187b Mon Sep 17 00:00:00 2001 From: RITUPARNA MANDAL Date: Wed, 5 Jun 2024 08:46:39 +0000 Subject: [PATCH 1/5] change default id in NewVerifiableCredentialBuilder as empty, validatesid is a parsable uri in SetID --- credential/builder.go | 8 ++++++-- credential/builder_test.go | 6 +++--- go.work.sum | 3 +++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/credential/builder.go b/credential/builder.go index b1eed6c6..b99e1b90 100644 --- a/credential/builder.go +++ b/credential/builder.go @@ -2,6 +2,7 @@ package credential import ( "fmt" + "net/url" "reflect" "github.com/google/uuid" @@ -31,6 +32,7 @@ type VerifiableCredentialBuilder struct { } // NewVerifiableCredentialBuilder returns an initialized credential builder with some default fields populated +// Default id is empty func NewVerifiableCredentialBuilder() VerifiableCredentialBuilder { contexts := []string{VerifiableCredentialsLinkedDataContext} types := []string{VerifiableCredentialType} @@ -38,7 +40,7 @@ func NewVerifiableCredentialBuilder() VerifiableCredentialBuilder { contexts: contexts, types: types, VerifiableCredential: &VerifiableCredential{ - ID: uuid.NewString(), + ID: "", Context: contexts, Type: types, IssuanceDate: util.GetRFC3339Timestamp(), @@ -85,7 +87,9 @@ func (vcb *VerifiableCredentialBuilder) SetID(id string) error { if vcb.IsEmpty() { return errors.New(BuilderEmptyError) } - + if _, err := url.Parse(id); err != nil { + return errors.Wrap(err, "malformed id") + } vcb.ID = id return nil } diff --git a/credential/builder_test.go b/credential/builder_test.go index 717bfd56..f3db0942 100644 --- a/credential/builder_test.go +++ b/credential/builder_test.go @@ -93,11 +93,11 @@ func TestCredentialBuilder(t *testing.T) { err = builder.AddContext("https://www.w3.org/2018/credentials/examples/v1") assert.NoError(t, err) - // there is a default id - assert.NotEmpty(t, builder.ID) + //default id is empty + assert.Empty(t, builder.ID) // set id - id := "test-id" + id := "p" err = builder.SetID(id) assert.NoError(t, err) diff --git a/go.work.sum b/go.work.sum index 16900942..1736fb19 100644 --- a/go.work.sum +++ b/go.work.sum @@ -224,6 +224,7 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= @@ -259,12 +260,14 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 94b2260c08f732c615a4417a92a649ace0be6041 Mon Sep 17 00:00:00 2001 From: RITUPARNA MANDAL Date: Thu, 6 Jun 2024 05:21:19 +0000 Subject: [PATCH 2/5] add option in NewVerifiableCredentialBuilder to set ID as empty, validates that Id is a parsable uri in SetID --- credential/builder.go | 12 +++++++++--- credential/builder_test.go | 12 ++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/credential/builder.go b/credential/builder.go index b99e1b90..082bbf11 100644 --- a/credential/builder.go +++ b/credential/builder.go @@ -33,19 +33,25 @@ type VerifiableCredentialBuilder struct { // NewVerifiableCredentialBuilder returns an initialized credential builder with some default fields populated // Default id is empty -func NewVerifiableCredentialBuilder() VerifiableCredentialBuilder { +func NewVerifiableCredentialBuilder(emptyID ...bool) VerifiableCredentialBuilder { contexts := []string{VerifiableCredentialsLinkedDataContext} types := []string{VerifiableCredentialType} - return VerifiableCredentialBuilder{ + id := uuid.NewString() + if len(emptyID)>0 && emptyID[0]{ + id = "" + } + vcb := VerifiableCredentialBuilder{ contexts: contexts, types: types, VerifiableCredential: &VerifiableCredential{ - ID: "", + ID: id, Context: contexts, Type: types, IssuanceDate: util.GetRFC3339Timestamp(), }, } + return vcb + } // Build attempts to turn a builder into a valid verifiable credential, doing some object model validation. diff --git a/credential/builder_test.go b/credential/builder_test.go index f3db0942..c78219bc 100644 --- a/credential/builder_test.go +++ b/credential/builder_test.go @@ -73,7 +73,11 @@ func TestCredential(t *testing.T) { // Exercise all builder methods func TestCredentialBuilder(t *testing.T) { - builder := NewVerifiableCredentialBuilder() + + builder := NewVerifiableCredentialBuilder(true) + assert.Empty(t, builder.ID) + + builder = NewVerifiableCredentialBuilder() _, err := builder.Build() assert.Error(t, err) notReadyErr := "credential not ready to be built" @@ -93,9 +97,9 @@ func TestCredentialBuilder(t *testing.T) { err = builder.AddContext("https://www.w3.org/2018/credentials/examples/v1") assert.NoError(t, err) - //default id is empty - assert.Empty(t, builder.ID) - + //default id is not empty + assert.NotEmpty(t, builder.ID) + // set id id := "p" err = builder.SetID(id) From 36763bbe0c060e5ed2465b8b0594957267fa90fb Mon Sep 17 00:00:00 2001 From: RITUPARNA MANDAL <32814143+m-rit@users.noreply.github.com> Date: Thu, 6 Jun 2024 00:36:04 -0500 Subject: [PATCH 3/5] add code comments for emptyID option --- credential/builder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/credential/builder.go b/credential/builder.go index 082bbf11..759f3330 100644 --- a/credential/builder.go +++ b/credential/builder.go @@ -32,7 +32,7 @@ type VerifiableCredentialBuilder struct { } // NewVerifiableCredentialBuilder returns an initialized credential builder with some default fields populated -// Default id is empty +// Setting emptyID as True creates VC with empty ID. Default ID is a random UUID. func NewVerifiableCredentialBuilder(emptyID ...bool) VerifiableCredentialBuilder { contexts := []string{VerifiableCredentialsLinkedDataContext} types := []string{VerifiableCredentialType} From ba8994a8bcebc7e6d24e28c5f8f6906aa89682e3 Mon Sep 17 00:00:00 2001 From: RITUPARNA MANDAL Date: Sun, 9 Jun 2024 18:43:55 +0000 Subject: [PATCH 4/5] Add ID options in VerifiableCredentialBuilder --- credential/builder.go | 23 +++++++++++++++++------ credential/builder_test.go | 9 ++++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/credential/builder.go b/credential/builder.go index 759f3330..50592d92 100644 --- a/credential/builder.go +++ b/credential/builder.go @@ -12,6 +12,8 @@ import ( "github.com/pkg/errors" ) +type IDValue string // IDValue represents different types of ID values for building Verifiable Credentials + const ( VerifiableCredentialsLinkedDataContext string = "https://www.w3.org/2018/credentials/v1" VerifiableCredentialType string = "VerifiableCredential" @@ -21,6 +23,9 @@ const ( VerifiablePresentationType string = "VerifiablePresentation" BuilderEmptyError string = "builder cannot be empty" + + EmptyIDValue IDValue = "" // EmptyIDValue indicates setting the ID value to empty + GenerateIDValue IDValue = "generate" // GenerateIDValue indicates generating a UUID as the ID value. ) // VerifiableCredentialBuilder uses the builder pattern to construct a verifiable credential @@ -32,14 +37,20 @@ type VerifiableCredentialBuilder struct { } // NewVerifiableCredentialBuilder returns an initialized credential builder with some default fields populated -// Setting emptyID as True creates VC with empty ID. Default ID is a random UUID. -func NewVerifiableCredentialBuilder(emptyID ...bool) VerifiableCredentialBuilder { +// idValue determines whether VC will have empty ID/ random UUID/ customID. +func NewVerifiableCredentialBuilder(idValue IDValue) VerifiableCredentialBuilder { contexts := []string{VerifiableCredentialsLinkedDataContext} types := []string{VerifiableCredentialType} - id := uuid.NewString() - if len(emptyID)>0 && emptyID[0]{ + var id string + switch { + case idValue == EmptyIDValue: id = "" + case idValue == GenerateIDValue: + id = uuid.NewString() + default: + id = string(idValue) } + vcb := VerifiableCredentialBuilder{ contexts: contexts, types: types, @@ -51,7 +62,7 @@ func NewVerifiableCredentialBuilder(emptyID ...bool) VerifiableCredentialBuilder }, } return vcb - + } // Build attempts to turn a builder into a valid verifiable credential, doing some object model validation. @@ -93,7 +104,7 @@ func (vcb *VerifiableCredentialBuilder) SetID(id string) error { if vcb.IsEmpty() { return errors.New(BuilderEmptyError) } - if _, err := url.Parse(id); err != nil { + if _, err := url.Parse(id); err != nil { return errors.Wrap(err, "malformed id") } vcb.ID = id diff --git a/credential/builder_test.go b/credential/builder_test.go index c78219bc..de3665a6 100644 --- a/credential/builder_test.go +++ b/credential/builder_test.go @@ -44,7 +44,7 @@ func TestCredential(t *testing.T) { assert.NoError(t, err) // re-build with our builder - builder := NewVerifiableCredentialBuilder() + builder := NewVerifiableCredentialBuilder(EmptyIDValue) err = builder.AddContext(knownContext) assert.NoError(t, err) @@ -74,10 +74,13 @@ func TestCredential(t *testing.T) { // Exercise all builder methods func TestCredentialBuilder(t *testing.T) { - builder := NewVerifiableCredentialBuilder(true) + builder := NewVerifiableCredentialBuilder(EmptyIDValue) assert.Empty(t, builder.ID) - builder = NewVerifiableCredentialBuilder() + builder = NewVerifiableCredentialBuilder(IDValue("customid-123")) + assert.Equal(t, builder.ID, "customid-123") + + builder = NewVerifiableCredentialBuilder(GenerateIDValue) _, err := builder.Build() assert.Error(t, err) notReadyErr := "credential not ready to be built" From 5b7cdfc65e8b91565a52fae75eb90b2bdce24c56 Mon Sep 17 00:00:00 2001 From: RITUPARNA MANDAL Date: Thu, 20 Jun 2024 09:40:09 +0000 Subject: [PATCH 5/5] update all instances of NewVerifiableCredentialBuilder to accept IDValue --- credential/status/statuslist2021.go | 2 +- example/manifest/manifest.go | 4 ++-- .../usecase/apartment_application/apartment_application.go | 2 +- example/usecase/steel_thread/steel_thread.go | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/credential/status/statuslist2021.go b/credential/status/statuslist2021.go index 47c53b5b..5e0dca9f 100644 --- a/credential/status/statuslist2021.go +++ b/credential/status/statuslist2021.go @@ -73,7 +73,7 @@ func GenerateStatusList2021Credential(id string, issuer string, purpose StatusPu EncodedList: bitString, } - builder := credential.NewVerifiableCredentialBuilder() + builder := credential.NewVerifiableCredentialBuilder(credential.GenerateIDValue) errMsgFragment := "could not generate status list credential: error setting " if err = builder.SetID(id); err != nil { return nil, errors.Wrap(err, errMsgFragment+"id") diff --git a/example/manifest/manifest.go b/example/manifest/manifest.go index de8ff951..8fc1e518 100644 --- a/example/manifest/manifest.go +++ b/example/manifest/manifest.go @@ -181,7 +181,7 @@ func prepareCredentialManifest(issuerDID key.DIDKey, licenseSchemaID string) (*m // Prepare a credential which is required to fill out the credential manifest's application's // input descriptor's requirements func issueApplicationCredential(id key.DIDKey, s schema.JSONSchema) (*credential.VerifiableCredential, error) { - builder := credential.NewVerifiableCredentialBuilder() + builder := credential.NewVerifiableCredentialBuilder(credential.GenerateIDValue) if err := builder.SetIssuer(id.String()); err != nil { return nil, err @@ -272,7 +272,7 @@ type driversLicenseFields struct { } func issueDriversLicenseCredential(issuerDID key.DIDKey, subjectDID string, s schema.JSONSchema, data driversLicenseFields) (*credential.VerifiableCredential, error) { - builder := credential.NewVerifiableCredentialBuilder() + builder := credential.NewVerifiableCredentialBuilder(credential.GenerateIDValue) if err := builder.SetIssuer(issuerDID.String()); err != nil { return nil, err diff --git a/example/usecase/apartment_application/apartment_application.go b/example/usecase/apartment_application/apartment_application.go index 46776b8a..22d510cb 100644 --- a/example/usecase/apartment_application/apartment_application.go +++ b/example/usecase/apartment_application/apartment_application.go @@ -76,7 +76,7 @@ func main() { "birthdate": "1975-01-01", } - vcBuilder := credential.NewVerifiableCredentialBuilder() + vcBuilder := credential.NewVerifiableCredentialBuilder(credential.GenerateIDValue) err = vcBuilder.SetIssuer(string(*knownIssuer)) example.HandleExampleError(err, "Failed to set issuer") diff --git a/example/usecase/steel_thread/steel_thread.go b/example/usecase/steel_thread/steel_thread.go index 249eccde..28e7a315 100644 --- a/example/usecase/steel_thread/steel_thread.go +++ b/example/usecase/steel_thread/steel_thread.go @@ -273,7 +273,7 @@ func createVerifiableCredential(issuerDID string, walletDID string) credential.V credSubject := vc.CredentialSubject credSubject["id"] = walletDID - builder := credential.NewVerifiableCredentialBuilder() + builder := credential.NewVerifiableCredentialBuilder(credential.GenerateIDValue) _ = builder.SetIssuer(issuerDID) _ = builder.SetCredentialSubject(credSubject) _ = builder.SetCredentialSchema(*vc.CredentialSchema)