github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/protocol/middleware/issuecredential/middlewares_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package issuecredential
     8  
     9  import (
    10  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/golang/mock/gomock"
    17  	"github.com/stretchr/testify/require"
    18  
    19  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
    20  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator"
    21  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/issuecredential"
    22  	"github.com/hyperledger/aries-framework-go/pkg/doc/did"
    23  	"github.com/hyperledger/aries-framework-go/pkg/doc/util"
    24  	"github.com/hyperledger/aries-framework-go/pkg/doc/verifiable"
    25  	mocks "github.com/hyperledger/aries-framework-go/pkg/internal/gomocks/didcomm/protocol/middleware/issuecredential"
    26  	mockvdr "github.com/hyperledger/aries-framework-go/pkg/internal/gomocks/framework/aries/api/vdr"
    27  	mockstore "github.com/hyperledger/aries-framework-go/pkg/internal/gomocks/store/verifiable"
    28  	"github.com/hyperledger/aries-framework-go/pkg/internal/ldtestutil"
    29  )
    30  
    31  func getCredential() *verifiable.Credential {
    32  	return &verifiable.Credential{
    33  		Context: []string{
    34  			"https://www.w3.org/2018/credentials/v1",
    35  			"https://www.w3.org/2018/credentials/examples/v1",
    36  		},
    37  		ID: "http://example.edu/credentials/1872",
    38  		Types: []string{
    39  			"VerifiableCredential",
    40  			"UniversityDegreeCredential",
    41  		},
    42  		Subject: struct {
    43  			ID string
    44  		}{ID: "SubjectID"},
    45  		Issuer: verifiable.Issuer{
    46  			ID:           "did:example:76e12ec712ebc6f1c221ebfeb1f",
    47  			CustomFields: verifiable.CustomFields{"name": "Example University"},
    48  		},
    49  		Issued:  util.NewTime(time.Date(2010, time.January, 1, 19, 23, 24, 0, time.UTC)),
    50  		Schemas: []verifiable.TypedID{},
    51  		CustomFields: map[string]interface{}{
    52  			"referenceNumber": 83294847,
    53  		},
    54  	}
    55  }
    56  
    57  func TestSaveCredentials(t *testing.T) {
    58  	ctrl := gomock.NewController(t)
    59  	defer ctrl.Finish()
    60  
    61  	provider := mocks.NewMockProvider(ctrl)
    62  	provider.EXPECT().VDRegistry().Return(nil).AnyTimes()
    63  	provider.EXPECT().VerifiableStore().Return(nil).AnyTimes()
    64  	provider.EXPECT().JSONLDDocumentLoader().Return(nil).AnyTimes()
    65  
    66  	next := issuecredential.HandlerFunc(func(metadata issuecredential.Metadata) error {
    67  		return nil
    68  	})
    69  
    70  	t.Run("Ignores processing", func(t *testing.T) {
    71  		metadata := mocks.NewMockMetadata(ctrl)
    72  		metadata.EXPECT().StateName().Return("state-name")
    73  		require.NoError(t, SaveCredentials(provider)(next).Handle(metadata))
    74  	})
    75  
    76  	t.Run("Credentials not provided", func(t *testing.T) {
    77  		metadata := mocks.NewMockMetadata(ctrl)
    78  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
    79  		metadata.EXPECT().Message().Return(service.NewDIDCommMsgMap(issuecredential.IssueCredentialV2{
    80  			Type: issuecredential.IssueCredentialMsgTypeV2,
    81  		}))
    82  		metadata.EXPECT().Properties().Return(map[string]interface{}{
    83  			myDIDKey:    myDIDKey,
    84  			theirDIDKey: theirDIDKey,
    85  		})
    86  
    87  		err := SaveCredentials(provider)(next).Handle(metadata)
    88  		require.EqualError(t, err, "credentials were not provided")
    89  	})
    90  
    91  	t.Run("Marshal credentials error", func(t *testing.T) {
    92  		metadata := mocks.NewMockMetadata(ctrl)
    93  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
    94  		metadata.EXPECT().Message().Return(service.NewDIDCommMsgMap(issuecredential.IssueCredentialV2{
    95  			Type: issuecredential.IssueCredentialMsgTypeV2,
    96  			CredentialsAttach: []decorator.Attachment{
    97  				{Data: decorator.AttachmentData{JSON: struct{ C chan int }{}}},
    98  			},
    99  		}))
   100  		metadata.EXPECT().Properties().Return(map[string]interface{}{
   101  			myDIDKey:    myDIDKey,
   102  			theirDIDKey: theirDIDKey,
   103  		})
   104  
   105  		err := SaveCredentials(provider)(next).Handle(metadata)
   106  		require.Contains(t, fmt.Sprintf("%v", err), "json: unsupported type")
   107  	})
   108  
   109  	t.Run("Decode error", func(t *testing.T) {
   110  		metadata := mocks.NewMockMetadata(ctrl)
   111  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
   112  		metadata.EXPECT().Message().Return(service.DIDCommMsgMap{"@type": map[int]int{}})
   113  		metadata.EXPECT().Properties().Return(map[string]interface{}{
   114  			myDIDKey:    myDIDKey,
   115  			theirDIDKey: theirDIDKey,
   116  		})
   117  
   118  		err := SaveCredentials(provider)(next).Handle(metadata)
   119  		require.Contains(t, fmt.Sprintf("%v", err), "got unconvertible type")
   120  	})
   121  
   122  	t.Run("Invalid credentials", func(t *testing.T) {
   123  		metadata := mocks.NewMockMetadata(ctrl)
   124  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
   125  		metadata.EXPECT().Message().Return(service.NewDIDCommMsgMap(issuecredential.IssueCredentialV2{
   126  			Type: issuecredential.IssueCredentialMsgTypeV2,
   127  			CredentialsAttach: []decorator.Attachment{
   128  				{Data: decorator.AttachmentData{JSON: &verifiable.Credential{
   129  					Context: []string{"https://www.w3.org/2018/credentials/v1"},
   130  				}}},
   131  			},
   132  		}))
   133  		metadata.EXPECT().Properties().Return(map[string]interface{}{
   134  			myDIDKey:    myDIDKey,
   135  			theirDIDKey: theirDIDKey,
   136  		})
   137  
   138  		err := SaveCredentials(provider)(next).Handle(metadata)
   139  		require.Contains(t, fmt.Sprintf("%v", err), "to verifiable credentials")
   140  	})
   141  
   142  	t.Run("DB error", func(t *testing.T) {
   143  		const (
   144  			vcName = "vc-name"
   145  			errMsg = "error message"
   146  		)
   147  
   148  		metadata := mocks.NewMockMetadata(ctrl)
   149  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
   150  		metadata.EXPECT().CredentialNames().Return([]string{vcName}).Times(2)
   151  		metadata.EXPECT().Properties().Return(map[string]interface{}{
   152  			myDIDKey:    myDIDKey,
   153  			theirDIDKey: theirDIDKey,
   154  		})
   155  		metadata.EXPECT().Message().Return(service.NewDIDCommMsgMap(issuecredential.IssueCredentialV2{
   156  			Type: issuecredential.IssueCredentialMsgTypeV2,
   157  			CredentialsAttach: []decorator.Attachment{
   158  				{Data: decorator.AttachmentData{JSON: getCredential()}},
   159  			},
   160  		}))
   161  
   162  		verifiableStore := mockstore.NewMockStore(ctrl)
   163  		verifiableStore.EXPECT().SaveCredential(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
   164  			Return(errors.New(errMsg))
   165  
   166  		loader, err := ldtestutil.DocumentLoader()
   167  		require.NoError(t, err)
   168  
   169  		p := mocks.NewMockProvider(ctrl)
   170  		p.EXPECT().VDRegistry().Return(nil).AnyTimes()
   171  		p.EXPECT().VerifiableStore().Return(verifiableStore)
   172  		p.EXPECT().JSONLDDocumentLoader().Return(loader)
   173  
   174  		require.EqualError(t, SaveCredentials(p)(next).Handle(metadata), "save credential: "+errMsg)
   175  	})
   176  
   177  	t.Run("No DIDs", func(t *testing.T) {
   178  		metadata := mocks.NewMockMetadata(ctrl)
   179  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
   180  		metadata.EXPECT().Properties().Return(map[string]interface{}{})
   181  		metadata.EXPECT().Message().Return(service.NewDIDCommMsgMap(issuecredential.IssueCredentialV2{
   182  			Type: issuecredential.IssueCredentialMsgTypeV2,
   183  			CredentialsAttach: []decorator.Attachment{
   184  				{Data: decorator.AttachmentData{JSON: getCredential()}},
   185  			},
   186  		}))
   187  
   188  		loader, err := ldtestutil.DocumentLoader()
   189  		require.NoError(t, err)
   190  
   191  		p := mocks.NewMockProvider(ctrl)
   192  		p.EXPECT().VDRegistry().Return(nil).AnyTimes()
   193  		p.EXPECT().VerifiableStore().Return(mockstore.NewMockStore(ctrl))
   194  		p.EXPECT().JSONLDDocumentLoader().Return(loader)
   195  
   196  		require.EqualError(t, SaveCredentials(p)(next).Handle(metadata), "myDID or theirDID is absent")
   197  	})
   198  
   199  	t.Run("Success", func(t *testing.T) {
   200  		const vcName = "vc-name"
   201  
   202  		props := map[string]interface{}{
   203  			myDIDKey:    myDIDKey,
   204  			theirDIDKey: theirDIDKey,
   205  		}
   206  
   207  		metadata := mocks.NewMockMetadata(ctrl)
   208  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
   209  		metadata.EXPECT().CredentialNames().Return([]string{vcName}).Times(2)
   210  		metadata.EXPECT().Properties().Return(props)
   211  		metadata.EXPECT().Message().Return(service.NewDIDCommMsgMap(issuecredential.IssueCredentialV2{
   212  			Type: issuecredential.IssueCredentialMsgTypeV2,
   213  			CredentialsAttach: []decorator.Attachment{
   214  				{Data: decorator.AttachmentData{JSON: getCredential()}},
   215  			},
   216  		}))
   217  
   218  		verifiableStore := mockstore.NewMockStore(ctrl)
   219  		verifiableStore.EXPECT().SaveCredential(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
   220  			Return(nil)
   221  
   222  		loader, err := ldtestutil.DocumentLoader()
   223  		require.NoError(t, err)
   224  
   225  		p := mocks.NewMockProvider(ctrl)
   226  		p.EXPECT().VDRegistry().Return(nil).AnyTimes()
   227  		p.EXPECT().VerifiableStore().Return(verifiableStore)
   228  		p.EXPECT().JSONLDDocumentLoader().Return(loader)
   229  
   230  		require.NoError(t, SaveCredentials(p)(next).Handle(metadata))
   231  		require.Equal(t, props["names"], []string{vcName})
   232  	})
   233  
   234  	t.Run("Success - no save", func(t *testing.T) {
   235  		props := map[string]interface{}{
   236  			myDIDKey:              myDIDKey,
   237  			theirDIDKey:           theirDIDKey,
   238  			SkipCredentialSaveKey: true,
   239  		}
   240  
   241  		metadata := mocks.NewMockMetadata(ctrl)
   242  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
   243  		metadata.EXPECT().Properties().Return(props)
   244  
   245  		require.NoError(t, SaveCredentials(provider)(next).Handle(metadata))
   246  	})
   247  
   248  	t.Run("Success V3", func(t *testing.T) {
   249  		const vcName = "vc-name"
   250  
   251  		props := map[string]interface{}{
   252  			myDIDKey:    myDIDKey,
   253  			theirDIDKey: theirDIDKey,
   254  		}
   255  
   256  		metadata := mocks.NewMockMetadata(ctrl)
   257  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
   258  		metadata.EXPECT().CredentialNames().Return([]string{vcName}).Times(2)
   259  		metadata.EXPECT().Properties().Return(props)
   260  		metadata.EXPECT().Message().Return(service.NewDIDCommMsgMap(issuecredential.IssueCredentialV3{
   261  			Type: issuecredential.IssueCredentialMsgTypeV3,
   262  			Attachments: []decorator.AttachmentV2{
   263  				{Data: decorator.AttachmentData{JSON: getCredential()}},
   264  			},
   265  		}))
   266  
   267  		verifiableStore := mockstore.NewMockStore(ctrl)
   268  		verifiableStore.EXPECT().SaveCredential(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
   269  			Return(nil)
   270  
   271  		loader, err := ldtestutil.DocumentLoader()
   272  		require.NoError(t, err)
   273  
   274  		provider := mocks.NewMockProvider(ctrl)
   275  		provider.EXPECT().VDRegistry().Return(nil).AnyTimes()
   276  		provider.EXPECT().VerifiableStore().Return(verifiableStore)
   277  		provider.EXPECT().JSONLDDocumentLoader().Return(loader)
   278  
   279  		require.NoError(t, SaveCredentials(provider)(next).Handle(metadata))
   280  		require.Equal(t, props["names"], []string{vcName})
   281  	})
   282  
   283  	t.Run("Success (no ID)", func(t *testing.T) {
   284  		props := map[string]interface{}{
   285  			myDIDKey:    myDIDKey,
   286  			theirDIDKey: theirDIDKey,
   287  		}
   288  
   289  		cred := getCredential()
   290  		cred.ID = ""
   291  
   292  		metadata := mocks.NewMockMetadata(ctrl)
   293  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
   294  		metadata.EXPECT().CredentialNames().Return([]string{})
   295  		metadata.EXPECT().Properties().Return(props)
   296  		metadata.EXPECT().Message().Return(service.NewDIDCommMsgMap(issuecredential.IssueCredentialV2{
   297  			Type: issuecredential.IssueCredentialMsgTypeV2,
   298  			CredentialsAttach: []decorator.Attachment{
   299  				{Data: decorator.AttachmentData{JSON: cred}},
   300  			},
   301  		}))
   302  
   303  		verifiableStore := mockstore.NewMockStore(ctrl)
   304  		verifiableStore.EXPECT().SaveCredential(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
   305  			Return(nil)
   306  
   307  		loader, err := ldtestutil.DocumentLoader()
   308  		require.NoError(t, err)
   309  
   310  		provider := mocks.NewMockProvider(ctrl)
   311  		provider.EXPECT().VDRegistry().Return(nil).AnyTimes()
   312  		provider.EXPECT().VerifiableStore().Return(verifiableStore)
   313  		provider.EXPECT().JSONLDDocumentLoader().Return(loader)
   314  
   315  		require.NoError(t, SaveCredentials(provider)(next).Handle(metadata))
   316  		require.Equal(t, len(props["names"].([]string)), 1)
   317  		require.NotEmpty(t, props["names"].([]string)[0])
   318  	})
   319  
   320  	t.Run("Success (credential with a proof)", func(t *testing.T) {
   321  		const vcName = "vc-name"
   322  
   323  		var credential map[string]interface{}
   324  		// nolint: lll
   325  		require.NoError(t, json.Unmarshal([]byte(`{
   326  				"@context": [
   327  					"https://www.w3.org/2018/credentials/v1",
   328  					"https://www.w3.org/2018/credentials/examples/v1"
   329  				],
   330  				"credentialSubject": {
   331  					"degree": {
   332  						"type": "BachelorDegree",
   333  						"university": "MIT"
   334  					},
   335  					"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
   336  					"name": "Jayden Doe",
   337  					"spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1"
   338  				},
   339  				"expirationDate": "2020-01-01T19:23:24Z",
   340  				"id": "http://example.edu/credentials/1872",
   341  				"issuanceDate": "2009-01-01T19:23:24Z",
   342  				"issuer": {
   343  					"id": "did:example:76e12ec712ebc6f1c221ebfeb1f",
   344  					"name": "Example University"
   345  				},
   346  				"proof": {
   347  					"created": "2010-01-01T19:23:24Z",
   348  					"jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..lrkhpRH4tWl6KzQKHlcyAwSm8qUTXIMSKmD3QASF_uI5QW8NWLxLebXmnQpIM8H7umhLA6dINSYVowcaPdpwBw",
   349  					"proofPurpose": "assertionMethod",
   350  					"type": "Ed25519Signature2018",
   351  					"verificationMethod": "did:example:123456#key1"
   352  				},
   353  				"referenceNumber": 83294849,
   354  				"type": [
   355  					"VerifiableCredential",
   356  					"UniversityDegreeCredential"
   357  				]
   358  			}`), &credential))
   359  
   360  		props := map[string]interface{}{
   361  			myDIDKey:    myDIDKey,
   362  			theirDIDKey: theirDIDKey,
   363  		}
   364  
   365  		metadata := mocks.NewMockMetadata(ctrl)
   366  		metadata.EXPECT().StateName().Return(stateNameCredentialReceived)
   367  		metadata.EXPECT().CredentialNames().Return([]string{vcName}).Times(2)
   368  		metadata.EXPECT().Properties().Return(props)
   369  		metadata.EXPECT().Message().Return(service.NewDIDCommMsgMap(issuecredential.IssueCredentialV2{
   370  			Type: issuecredential.IssueCredentialMsgTypeV2,
   371  			CredentialsAttach: []decorator.Attachment{
   372  				{Data: decorator.AttachmentData{JSON: credential}},
   373  			},
   374  		}))
   375  
   376  		verifiableStore := mockstore.NewMockStore(ctrl)
   377  		verifiableStore.EXPECT().SaveCredential(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
   378  			Return(nil)
   379  
   380  		loader, err := ldtestutil.DocumentLoader()
   381  		require.NoError(t, err)
   382  
   383  		registry := mockvdr.NewMockRegistry(ctrl)
   384  		registry.EXPECT().Resolve("did:example:123456").Return(&did.DocResolution{DIDDocument: &did.Doc{
   385  			VerificationMethod: []did.VerificationMethod{{
   386  				ID: "#key1",
   387  				Value: []byte{
   388  					234, 100, 192, 93, 251, 181, 198, 73, 122, 220, 27, 48, 93, 73, 166,
   389  					33, 152, 140, 168, 36, 9, 205, 59, 161, 137, 7, 164, 9, 176, 252, 1, 171,
   390  				},
   391  			}},
   392  		}}, nil)
   393  
   394  		provider := mocks.NewMockProvider(ctrl)
   395  		provider.EXPECT().VDRegistry().Return(registry).AnyTimes()
   396  		provider.EXPECT().VerifiableStore().Return(verifiableStore)
   397  		provider.EXPECT().JSONLDDocumentLoader().Return(loader)
   398  
   399  		require.NoError(t, SaveCredentials(provider)(next).Handle(metadata))
   400  		require.Equal(t, props["names"], []string{vcName})
   401  	})
   402  }