diff --git a/vc/vc.go b/vc/vc.go index 0580753..cffa38b 100644 --- a/vc/vc.go +++ b/vc/vc.go @@ -142,7 +142,7 @@ type VerifiableCredential struct { IssuanceDate time.Time `json:"issuanceDate"` // ExpirationDate is a rfc3339 formatted datetime. It is optional ExpirationDate *time.Time `json:"expirationDate,omitempty"` - // CredentialStatus holds information on how the credential can be revoked. It is optional + // CredentialStatus holds information on how the credential can be revoked. It must be extracted using the UnmarshalCredentialStatus method and a custom type. It is optional CredentialStatus *CredentialStatus `json:"credentialStatus,omitempty"` // CredentialSubject holds the actual data for the credential. It must be extracted using the UnmarshalCredentialSubject method and a custom type. CredentialSubject []interface{} `json:"credentialSubject"` @@ -245,6 +245,16 @@ func (vc VerifiableCredential) UnmarshalCredentialSubject(target interface{}) er } } +// UnmarshalCredentialStatus unmarshalls the credentialStatus field to the provided target. +func (vc VerifiableCredential) UnmarshalCredentialStatus(target any) error { + type VC struct { + Target any `json:"credentialStatus"` + } + + cs := VC{Target: target} + return json.Unmarshal([]byte(vc.Raw()), &cs) +} + // SubjectDID returns the credential subject's ID as DID (credentialSubject.id). // If there are multiple subjects, all subjects must have the same ID. // It returns an error when: diff --git a/vc/vc_test.go b/vc/vc_test.go index bf0f91c..47db5a9 100644 --- a/vc/vc_test.go +++ b/vc/vc_test.go @@ -138,6 +138,32 @@ func TestVerifiableCredential_UnmarshalCredentialSubject(t *testing.T) { }) } +func TestVerifiableCredential_UnmarshalCredentialStatus(t *testing.T) { + // custom status that contains more fields than CredentialStatus + type CustomCredentialStatus struct { + Id string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + CustomField string `json:"customField,omitempty"` + } + expectedJSON := ` + { "credentialStatus": { + "type": "CustomType", + "customField": "not empty" + } + }` + t.Run("ok", func(t *testing.T) { + input := VerifiableCredential{} + json.Unmarshal([]byte(expectedJSON), &input) + var target CustomCredentialStatus + + err := input.UnmarshalCredentialStatus(&target) + + assert.NoError(t, err) + assert.Equal(t, "CustomType", target.Type) + assert.Equal(t, "not empty", target.CustomField) + }) +} + func TestCredentialStatus(t *testing.T) { t.Run("can unmarshal JWT VC Presentation Profile JWT-VC example", func(t *testing.T) { // CredentialStatus example taken from https://identity.foundation/jwt-vc-presentation-profile/#vc-jwt