github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/cm/credentialresponse_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package cm_test 8 9 import ( 10 _ "embed" 11 "encoding/json" 12 "reflect" 13 "testing" 14 15 "github.com/stretchr/testify/require" 16 17 "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/issuecredential" 18 "github.com/hyperledger/aries-framework-go/pkg/doc/cm" 19 "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" 20 ) 21 22 var ( 23 //go:embed testdata/credential_response_university_degree.json 24 validCredentialResponse []byte //nolint:gochecknoglobals 25 //go:embed testdata/issue_credential_message_university_degree.json 26 validIssueCredentialMessage []byte //nolint:gochecknoglobals 27 //go:embed testdata/VP_with_drivers_license_VC.json 28 vpWithDriversLicenseVC []byte //nolint:gochecknoglobals 29 //go:embed testdata/VP_with_drivers_license_VC_and_credential_response.json 30 vpWithDriversLicenseVCAndCredentialResponse []byte //nolint:gochecknoglobals 31 // The "minimal" VP below is ones that was created by a call to verifiable.NewPresentation() with no 32 // arguments/options, which is how the cm.PresentCredentialResponse method generates a VP if the 33 // WithExistingPresentationForPresentCredentialResponse option is not used. 34 //go:embed testdata/VP_minimal_with_credential_response.json 35 vpMinimalWithCredentialResponse []byte //nolint:gochecknoglobals 36 //go:embed testdata/VP_with_multiple_VCs_and_credential_response.json 37 vpMultipleWithCredentialResponse []byte //nolint:gochecknoglobals 38 ) 39 40 func TestCredentialResponse_Unmarshal(t *testing.T) { 41 t.Run("Valid Credential Response", func(t *testing.T) { 42 makeValidCredentialResponse(t) 43 }) 44 t.Run("Missing ID", func(t *testing.T) { 45 credentialResponseBytes := makeCredentialResponseWithMissingID(t) 46 47 var credentialResponse cm.CredentialResponse 48 49 err := json.Unmarshal(credentialResponseBytes, &credentialResponse) 50 require.EqualError(t, err, "invalid Credential Response: missing ID") 51 }) 52 t.Run("Missing Manifest ID", func(t *testing.T) { 53 credentialResponseBytes := makeCredentialResponseWithMissingManifestID(t) 54 55 var credentialResponse cm.CredentialResponse 56 57 err := json.Unmarshal(credentialResponseBytes, &credentialResponse) 58 require.EqualError(t, err, "invalid Credential Response: missing manifest ID") 59 }) 60 } 61 62 func TestCredentialResponse_ResolveDescriptorMap(t *testing.T) { 63 testDocumentLoaderOption := verifiable.WithJSONLDDocumentLoader(createTestDocumentLoader(t)) 64 65 t.Run("Success", func(t *testing.T) { 66 credentialResponse := makeValidCredentialResponse(t) 67 issueCredentialMessage := makeValidIssueCredentialMessage(t) 68 69 verifiableCredentials, err := credentialResponse.ResolveDescriptorMaps( 70 issueCredentialMessage.Attachments[0].Data.JSON, testDocumentLoaderOption) 71 require.NoError(t, err) 72 require.Len(t, verifiableCredentials, 1) 73 74 originalVC := getVCFromValidIssueCredentialMessage(t) 75 76 require.True(t, reflect.DeepEqual(verifiableCredentials[0], originalVC), 77 "resolved VC differs from the original VC") 78 }) 79 t.Run("Invalid JSONPath", func(t *testing.T) { 80 credentialResponse := makeCredentialResponseWithInvalidJSONPath(t) 81 issueCredentialMessage := makeValidIssueCredentialMessage(t) 82 83 verifiableCredentials, err := credentialResponse.ResolveDescriptorMaps( 84 issueCredentialMessage.Attachments[0].Data.JSON, testDocumentLoaderOption) 85 require.EqualError(t, err, "failed to resolve descriptor map at index 0: parsing error: "+ 86 `%InvalidJSONPath :1:1 - 1:2 unexpected "%" while scanning extensions`) 87 require.Nil(t, verifiableCredentials) 88 }) 89 t.Run("JSON data is not a map[string]interface{}", func(t *testing.T) { 90 credentialResponse := makeValidCredentialResponse(t) 91 92 verifiableCredentials, err := credentialResponse.ResolveDescriptorMaps(1) 93 require.EqualError(t, err, "the given JSON data could not be asserted as a map[string]interface{}") 94 require.Nil(t, verifiableCredentials) 95 }) 96 t.Run("Failed to parse VC", func(t *testing.T) { 97 credentialResponse := makeValidCredentialResponse(t) 98 issueCredentialMessage := makeIssueCredentialMessageWithInvalidVC(t) 99 100 verifiableCredentials, err := credentialResponse.ResolveDescriptorMaps( 101 issueCredentialMessage.Attachments[0].Data.JSON) 102 require.EqualError(t, err, "failed to resolve descriptor map at index 0: failed to parse "+ 103 "credential: decode new credential: embedded proof is not JSON: json: cannot unmarshal string "+ 104 "into Go value of type map[string]interface {}") 105 require.Nil(t, verifiableCredentials) 106 }) 107 } 108 109 func TestPresentCredentialResponse(t *testing.T) { 110 t.Run("Without using WithExistingPresentationForPresentCredentialResponse option", func(t *testing.T) { 111 credentialManifest := makeCredentialManifestFromBytes(t, credentialManifestDriversLicenseWithPresentationDefinition) 112 113 presentation, err := cm.PresentCredentialResponse(&credentialManifest) 114 require.NoError(t, err) 115 require.NotNil(t, presentation) 116 117 expectedPresentation := makePresentationFromBytes(t, vpMinimalWithCredentialResponse, 118 "Present Credential Response without existing Presentation") 119 120 reunmarshalledPresentation := marshalThenUnmarshalAgain(t, presentation, 121 "Present Credential Response without existing presentation") 122 123 makeCredentialResponseIDsTheSame(t, reunmarshalledPresentation, expectedPresentation) 124 require.True(t, reflect.DeepEqual(reunmarshalledPresentation, expectedPresentation), 125 "the presentation with a Credential Response added to it differs from what was expected") 126 }) 127 t.Run("Using WithExistingPresentationForPresentCredentialResponse option", func(t *testing.T) { 128 t.Run("CustomFields is not nil", func(t *testing.T) { 129 testName := "Present Credential Response with existing presentation, CustomFields is not nil" 130 131 presentation := makePresentationFromBytes(t, vpWithDriversLicenseVC, testName) 132 133 doPresentCredentialResponseTestWithExistingPresentation(t, presentation, testName) 134 }) 135 t.Run("CustomFields is nil", func(t *testing.T) { 136 testName := "Present Credential Response with existing presentation, CustomFields is nil" 137 138 presentation := makePresentationFromBytes(t, vpWithDriversLicenseVC, testName) 139 140 presentation.CustomFields = nil 141 142 doPresentCredentialResponseTestWithExistingPresentation(t, presentation, testName) 143 }) 144 }) 145 } 146 147 func doPresentCredentialResponseTestWithExistingPresentation(t *testing.T, 148 presentationToAddCredentialResponseTo *verifiable.Presentation, testName string) { 149 credentialManifest := makeCredentialManifestFromBytes(t, credentialManifestDriversLicenseWithPresentationDefinition) 150 151 presentationWithAddedCredentialResponse, err := cm.PresentCredentialResponse(&credentialManifest, 152 cm.WithExistingPresentationForPresentCredentialResponse(presentationToAddCredentialResponseTo)) 153 require.NoError(t, err) 154 155 expectedPresentation := makePresentationFromBytes(t, vpWithDriversLicenseVCAndCredentialResponse, testName) 156 157 reunmarshalledPresentation := marshalThenUnmarshalAgain(t, presentationWithAddedCredentialResponse, testName) 158 159 makeCredentialResponseIDsTheSame(t, reunmarshalledPresentation, expectedPresentation) 160 161 require.True(t, reflect.DeepEqual(reunmarshalledPresentation, expectedPresentation), 162 "the presentation with a Credential Response added to it differs from what was expected") 163 } 164 165 // The credential Response ID is randomly generated in the PresentCredentialResponse method, so this method 166 // is useful for allowing two presentations created by that method to be compared using reflect.DeepEqual. 167 func makeCredentialResponseIDsTheSame(t *testing.T, presentation1, 168 presentation2 *verifiable.Presentation) { 169 credentialResponseFromPresentation1, ok := 170 presentation1.CustomFields["credential_response"].(map[string]interface{}) 171 require.True(t, ok) 172 173 credentialResponseFromPresentation2, ok := 174 presentation2.CustomFields["credential_response"].(map[string]interface{}) 175 require.True(t, ok) 176 177 credentialResponseFromPresentation2["id"] = credentialResponseFromPresentation1["id"] 178 } 179 180 func makeValidCredentialResponse(t *testing.T) cm.CredentialResponse { 181 var credentialResponse cm.CredentialResponse 182 183 err := json.Unmarshal(validCredentialResponse, &credentialResponse) 184 require.NoError(t, err) 185 186 return credentialResponse 187 } 188 189 func makeValidIssueCredentialMessage(t *testing.T) issuecredential.IssueCredentialV3 { 190 var issueCredentialMessage issuecredential.IssueCredentialV3 191 192 err := json.Unmarshal(validIssueCredentialMessage, &issueCredentialMessage) 193 require.NoError(t, err) 194 195 return issueCredentialMessage 196 } 197 198 func getVCFromValidIssueCredentialMessage(t *testing.T) verifiable.Credential { 199 issueCredentialMessage := makeValidIssueCredentialMessage(t) 200 201 jsonAttachmentAsMap, ok := issueCredentialMessage.Attachments[0].Data.JSON.(map[string]interface{}) 202 require.True(t, ok) 203 204 verifiableCredentialsRaw := jsonAttachmentAsMap["verifiableCredential"] 205 206 verifiableCredentialsAsArrayOfInterface, ok := verifiableCredentialsRaw.([]interface{}) 207 require.True(t, ok) 208 209 vcBytes, err := json.Marshal(verifiableCredentialsAsArrayOfInterface[0]) 210 require.NoError(t, err) 211 212 vc, err := verifiable.ParseCredential(vcBytes, verifiable.WithJSONLDDocumentLoader(createTestDocumentLoader(t))) 213 require.NoError(t, err) 214 215 return *vc 216 } 217 218 func makeCredentialResponseWithMissingID(t *testing.T) []byte { 219 credentialResponse := makeValidCredentialResponse(t) 220 221 credentialResponse.ID = "" 222 223 credentialResponseBytes, err := json.Marshal(credentialResponse) 224 require.NoError(t, err) 225 226 return credentialResponseBytes 227 } 228 229 func makeCredentialResponseWithMissingManifestID(t *testing.T) []byte { 230 credentialResponse := makeValidCredentialResponse(t) 231 232 credentialResponse.ManifestID = "" 233 234 credentialResponseBytes, err := json.Marshal(credentialResponse) 235 require.NoError(t, err) 236 237 return credentialResponseBytes 238 } 239 240 func makeCredentialResponseWithInvalidJSONPath(t *testing.T) cm.CredentialResponse { 241 credentialResponse := makeValidCredentialResponse(t) 242 243 credentialResponse.OutputDescriptorMappingObjects[0].Path = invalidJSONPath 244 245 return credentialResponse 246 } 247 248 func makeIssueCredentialMessageWithInvalidVC(t *testing.T) issuecredential.IssueCredentialV3 { 249 var issueCredentialMessage issuecredential.IssueCredentialV3 250 251 err := json.Unmarshal(validIssueCredentialMessage, &issueCredentialMessage) 252 require.NoError(t, err) 253 254 jsonAttachmentAsMap, ok := issueCredentialMessage.Attachments[0].Data.JSON.(map[string]interface{}) 255 require.True(t, ok) 256 257 jsonAttachmentAsMap["verifiableCredential"] = []interface{}{"NotAValidVC"} 258 259 return issueCredentialMessage 260 }