From 9be06e7d1f4ee14b0f46466ae273cdc5e32638a2 Mon Sep 17 00:00:00 2001 From: Sandra Vrtikapa Date: Wed, 22 Jan 2020 18:37:04 -0500 Subject: [PATCH] feat: Sign and Verify VC (JSONLD Signature) User verifiable package to add signature to VC Verify signed VC Closes #24 Signed-off-by: Sandra Vrtikapa --- pkg/restapi/vc/operation/models.go | 22 ++- pkg/restapi/vc/operation/operations.go | 144 +++++++++++---- pkg/restapi/vc/operation/operations_test.go | 190 +++++++++++++------- pkg/restapi/vc/operation/profile.go | 9 +- pkg/restapi/vc/operation/profile_test.go | 11 +- 5 files changed, 256 insertions(+), 120 deletions(-) diff --git a/pkg/restapi/vc/operation/models.go b/pkg/restapi/vc/operation/models.go index 7013ea297..39a710f56 100644 --- a/pkg/restapi/vc/operation/models.go +++ b/pkg/restapi/vc/operation/models.go @@ -12,25 +12,31 @@ import ( "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" ) -// CreateCrendential input data for edge service issuer rest api -type CreateCrendential struct { +// CreateCredential input data for edge service issuer rest api +type CreateCredential struct { Subject verifiable.Subject `json:"credentialSubject"` Issuer verifiable.Issuer `json:"issuer"` Type []string `json:"type,omitempty"` + Profile string `json:"profile,omitempty"` } // ProfileRequest struct the input for creating profile type ProfileRequest struct { - DID string `json:"did"` - URI string `json:"uri"` + Name string `json:"name"` + DID string `json:"did"` + URI string `json:"uri"` + SignatureType string `json:"signatureType"` + Creator string `json:"creator"` } // ProfileResponse struct the output for creating profile type ProfileResponse struct { - ID string `json:"id"` - URI string `json:"uri"` - IssueDate *time.Time `json:"issueDate"` - DID string `json:"did"` + Name string `json:"name"` + DID string `json:"did"` + URI string `json:"uri"` + SignatureType string `json:"signatureType"` + Creator string `json:"creator"` + IssueDate *time.Time `json:"issueDate"` } // VerifyCredentialResponse describes verify credential response diff --git a/pkg/restapi/vc/operation/operations.go b/pkg/restapi/vc/operation/operations.go index 89bcc751a..f83a9dd61 100644 --- a/pkg/restapi/vc/operation/operations.go +++ b/pkg/restapi/vc/operation/operations.go @@ -7,6 +7,8 @@ SPDX-License-Identifier: Apache-2.0 package operation import ( + "crypto/ed25519" + "crypto/rand" "encoding/json" "errors" "fmt" @@ -14,12 +16,11 @@ import ( "io/ioutil" "net/http" "net/url" - "path" "time" "github.com/google/uuid" "github.com/gorilla/mux" - + "github.com/hyperledger/aries-framework-go/pkg/doc/signature/ed25519signature2018" "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" log "github.com/sirupsen/logrus" "github.com/trustbloc/edge-core/pkg/storage" @@ -39,9 +40,6 @@ const ( profilePathVariable = "profileID" successMsg = "success" - - // TODO create the profile and get the prefix of the ID from the profile issue-47 - id = "https://example.com/credentials/1872" ) var errProfileNotFound = errors.New("specified profile ID does not exist") @@ -60,10 +58,30 @@ func New(provider storage.Provider) (*Operation, error) { return nil, err } - profileStore := NewProfile(store) + // TODO: replace by KMS + pubKey, privKey, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, err + } + svc := &Operation{ - profileStore: profileStore, + profileStore: NewProfile(store), + // TODO: replace private key by signer, public key by resolver + keySet: &keySet{private: privKey, public: pubKey}, } + + // TODO: Remove default profile when bdd test is done + err = svc.profileStore.SaveProfile(&ProfileResponse{ + Name: "issuer", + DID: "did:method:abc", + URI: "https://issuer.com/credentials", + SignatureType: "Ed25519Signature2018", + Creator: "did:method:abc#key1", + }) + if err != nil { + return nil, err + } + svc.registerHandler() return svc, nil @@ -73,10 +91,17 @@ func New(provider storage.Provider) (*Operation, error) { type Operation struct { handlers []Handler profileStore *Profile + keySet *keySet +} + +// KeySet will be replaced with KMS/profile configuration +type keySet struct { + private []byte + public []byte } func (c *Operation) createCredentialHandler(rw http.ResponseWriter, req *http.Request) { - data := CreateCrendential{} + data := CreateCredential{} err := json.NewDecoder(req.Body).Decode(&data) if err != nil { @@ -85,22 +110,52 @@ func (c *Operation) createCredentialHandler(rw http.ResponseWriter, req *http.Re return } - validCredential, err := createCredential(&data) + profile, err := c.profileStore.GetProfile(data.Profile) + if err != nil { + c.writeErrorResponse(rw, http.StatusBadRequest, fmt.Sprintf("failed to read profile: %s", err.Error())) + + return + } + validCredential, err := createCredential(profile, &data) if err != nil { - c.writeErrorResponse(rw, http.StatusBadRequest, "Failed to write response for create credential failure") + c.writeErrorResponse(rw, http.StatusBadRequest, fmt.Sprintf("failed to create credential: %s", err.Error())) + + return + } + + signedVC, err := c.signCredential(profile, validCredential) + if err != nil { + c.writeErrorResponse(rw, http.StatusInternalServerError, fmt.Sprintf("failed to sign credential: %s", err.Error())) return } rw.WriteHeader(http.StatusCreated) - c.writeResponse(rw, validCredential) + c.writeResponse(rw, signedVC) +} + +func (c *Operation) signCredential(profile *ProfileResponse, vc *verifiable.Credential) (*verifiable.Credential, error) { // nolint:lll + signingCtx := &verifiable.LinkedDataProofContext{ + Creator: profile.Creator, + SignatureType: profile.SignatureType, + Suite: ed25519signature2018.New(), + PrivateKey: c.keySet.private, + } + + err := vc.AddLinkedDataProof(signingCtx) + if err != nil { + return nil, err + } + + return vc, nil } func (c *Operation) verifyCredentialHandler(rw http.ResponseWriter, req *http.Request) { body, err := ioutil.ReadAll(req.Body) if err != nil { - c.writeErrorResponse(rw, http.StatusBadRequest, fmt.Sprintf("failed to read request body: %s", err.Error())) + c.writeErrorResponse(rw, http.StatusBadRequest, + fmt.Sprintf("failed to read request body: %s", err.Error())) return } @@ -108,7 +163,11 @@ func (c *Operation) verifyCredentialHandler(rw http.ResponseWriter, req *http.Re verified := true message := successMsg - _, _, err = verifiable.NewCredential(body) + // Q: should signature suite this be passed in or handled (loaded automatically) by verifiable package + // based on signature type in proof + // Q: we should have default implementation for key fetcher in verifiable package as well + _, _, err = verifiable.NewCredential(body, verifiable.WithEmbeddedSignatureSuites(ed25519signature2018.New()), + verifiable.WithPublicKeyFetcher(verifiable.SingleKey(c.keySet.public))) if err != nil { verified = false message = err.Error() @@ -164,7 +223,7 @@ func (c *Operation) getProfileHandler(rw http.ResponseWriter, req *http.Request) c.writeResponse(rw, profileResponseJSON) } -func createCredential(data *CreateCrendential) (*verifiable.Credential, error) { +func createCredential(profile *ProfileResponse, data *CreateCredential) (*verifiable.Credential, error) { credential := &verifiable.Credential{} issueDate := time.Now().UTC() @@ -173,8 +232,7 @@ func createCredential(data *CreateCrendential) (*verifiable.Credential, error) { credential.Types = data.Type credential.Issuer = data.Issuer credential.Issued = &issueDate - // TODO to be replaced by getting profile ID issue-47 - credential.ID = id + credential.ID = profile.URI + "/" + uuid.New().String() cred, err := json.Marshal(credential) if err != nil { @@ -190,43 +248,55 @@ func createCredential(data *CreateCrendential) (*verifiable.Credential, error) { } func (c *Operation) createProfile(pr *ProfileRequest) (*ProfileResponse, error) { - if pr.DID == "" { - return nil, fmt.Errorf("missing DID information") - } - - if pr.URI == "" { - return nil, fmt.Errorf("missing URI information") - } - - u, err := parseAndGetURI(pr.URI) - if err != nil { + if err := validateProfileRequest(pr); err != nil { return nil, err } issueDate := time.Now().UTC() profileResponse := &ProfileResponse{ - ID: uuid.New().String(), - URI: u, - IssueDate: &issueDate, - DID: pr.DID, + Name: pr.Name, + URI: pr.URI, + IssueDate: &issueDate, + DID: pr.DID, + SignatureType: pr.SignatureType, + Creator: pr.Creator, } - err = c.profileStore.SaveProfile(profileResponse) + err := c.profileStore.SaveProfile(profileResponse) if err != nil { return nil, err } return profileResponse, nil } -func parseAndGetURI(uri string) (string, error) { - u, err := url.Parse(uri) - if err != nil { - return "", fmt.Errorf("failed to parse the uri: %s", err.Error()) + +func validateProfileRequest(pr *ProfileRequest) error { + if pr.Name == "" { + return fmt.Errorf("missing profile name") } - u.Path = path.Join(u.Path, uuid.New().String()) + if pr.DID == "" { + return fmt.Errorf("missing DID information") + } + + if pr.URI == "" { + return fmt.Errorf("missing URI information") + } + + if pr.Creator == "" { + return fmt.Errorf("missing creator") + } + + if pr.SignatureType == "" { + return fmt.Errorf("missing signature type") + } + + _, err := url.Parse(pr.URI) + if err != nil { + return fmt.Errorf("invalid uri: %s", err.Error()) + } - return u.String(), nil + return nil } // writeResponse writes interface value to response diff --git a/pkg/restapi/vc/operation/operations_test.go b/pkg/restapi/vc/operation/operations_test.go index 1fd3e7601..bb74a378f 100644 --- a/pkg/restapi/vc/operation/operations_test.go +++ b/pkg/restapi/vc/operation/operations_test.go @@ -22,8 +22,7 @@ import ( "github.com/trustbloc/edge-core/pkg/storage/memstore" ) -const ( - testCreateCredentialRequest = `{ +const testCreateCredentialRequest = `{ "context":"https://www.w3.org/2018/credentials/examples/v1", "type": [ "VerifiableCredential", @@ -38,15 +37,18 @@ const ( "name": "Jayden Doe", "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1" }, - + "profile": "issuer", "issuer": { "id": "did:example:76e12ec712ebc6f1c221ebfeb1f", "name": "Example University" } }` -) -const ( - testIncorrectCredential = `{ + +const testInvalidProfileForCreateCredential = `{ + "profile": "invalid" +}` + +const testIncorrectCredential = `{ "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", "degree": { @@ -56,25 +58,20 @@ const ( "name": "Jayden Doe", "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1" }, - + "profile": "test", "issuer": { "id": "did:example:76e12ec712ebc6f1c221ebfeb1f", "name": "Example University" } }` -) -const ( - testIssuerProfile = `{ - "did": "did:peer:22", - "uri": "https://example.com/credentials" -}` -) -const ( - testIncorrectIssuerProfile = `{ + +const testIssuerProfile = `{ + "name": "issuer", "did": "did:peer:22", - "uri": "&&%^)$" + "uri": "https://example.com/credentials", + "signatureType": "Ed25519Signature2018", + "creator": "did:peer:22#key1" }` -) const validVC = `{ "@context": "https://www.w3.org/2018/credentials/v1", @@ -105,6 +102,9 @@ func TestCreateCredentialHandler(t *testing.T) { op, err := New(memstore.NewProvider()) require.NoError(t, err) + err = op.profileStore.SaveProfile(getTestProfile()) + require.NoError(t, err) + createCredentialHandler := getHandler(t, op, createCredentialEndpoint) var logContents bytes.Buffer @@ -126,7 +126,6 @@ func TestCreateCredentialHandler(t *testing.T) { require.Equal(t, http.StatusCreated, rr.Code) require.Equal(t, "did:example:76e12ec712ebc6f1c221ebfeb1f", vc.Issuer.ID) require.Equal(t, "Example University", vc.Issuer.Name) - require.Equal(t, id, vc.ID) }) t.Run("create credential error by passing invalid request", func(t *testing.T) { req, err := http.NewRequest(http.MethodPost, createCredentialEndpoint, bytes.NewBuffer([]byte(""))) @@ -137,6 +136,15 @@ func TestCreateCredentialHandler(t *testing.T) { require.Equal(t, http.StatusBadRequest, rr.Code) require.Equal(t, rr.Body.String(), "Failed to write response for invalid request received") }) + t.Run("create credential error by passing invalid profile name", func(t *testing.T) { + req, err := http.NewRequest(http.MethodPost, createCredentialEndpoint, + bytes.NewBuffer([]byte(testInvalidProfileForCreateCredential))) + require.NoError(t, err) + rr := httptest.NewRecorder() + createCredentialHandler.Handle().ServeHTTP(rr, req) + require.Equal(t, http.StatusBadRequest, rr.Code) + require.Contains(t, rr.Body.String(), "failed to read profile") + }) t.Run("create credential error by passing invalid credential object", func(t *testing.T) { req, err := http.NewRequest(http.MethodPost, createCredentialEndpoint, bytes.NewBuffer([]byte(testIncorrectCredential))) @@ -144,8 +152,7 @@ func TestCreateCredentialHandler(t *testing.T) { rr := httptest.NewRecorder() createCredentialHandler.Handle().ServeHTTP(rr, req) require.Equal(t, http.StatusBadRequest, rr.Code) - require.Equal(t, rr.Body.String(), - "Failed to write response for create credential failure") + require.Contains(t, rr.Body.String(), "failed to create credential") }) t.Run("create credential error unable to write a response while reading the request", func(t *testing.T) { req, err := http.NewRequest(http.MethodPost, createCredentialEndpoint, bytes.NewBuffer([]byte(""))) @@ -157,6 +164,28 @@ func TestCreateCredentialHandler(t *testing.T) { }) } +func TestCreateCredentialHandler_SignatureError(t *testing.T) { + op, err := New(memstore.NewProvider()) + require.NoError(t, err) + + err = op.profileStore.SaveProfile(getTestProfile()) + require.NoError(t, err) + + // clear private key + op.keySet.private = nil + + createCredentialHandler := getHandler(t, op, createCredentialEndpoint) + + req, err := http.NewRequest(http.MethodPost, createCredentialEndpoint, + bytes.NewBuffer([]byte(testCreateCredentialRequest))) + require.NoError(t, err) + + rr := httptest.NewRecorder() + createCredentialHandler.Handle().ServeHTTP(rr, req) + require.Equal(t, http.StatusInternalServerError, rr.Code) + require.Contains(t, rr.Body.String(), "failed to sign credential") +} + func TestVerifyCredentialHandler(t *testing.T) { op, err := New(memstore.NewProvider()) require.NoError(t, err) @@ -229,22 +258,11 @@ func TestCreateProfileHandler(t *testing.T) { require.NoError(t, err) require.Equal(t, http.StatusCreated, rr.Code) - require.NotEmpty(t, profile.ID) + require.NotEmpty(t, profile.Name) require.Contains(t, profile.URI, "https://example.com/credentials") }) - t.Run("missing DID information", func(t *testing.T) { - prBytes, err := json.Marshal(ProfileRequest{}) - require.NoError(t, err) - req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, bytes.NewBuffer(prBytes)) - require.NoError(t, err) - rr := httptest.NewRecorder() - - createProfileHandler.Handle().ServeHTTP(rr, req) - require.Equal(t, http.StatusBadRequest, rr.Code) - require.Equal(t, rr.Body.String(), "missing DID information") - }) - t.Run("missing URI information", func(t *testing.T) { + t.Run("missing profile name", func(t *testing.T) { prBytes, err := json.Marshal(ProfileRequest{DID: "test"}) require.NoError(t, err) @@ -254,7 +272,7 @@ func TestCreateProfileHandler(t *testing.T) { createProfileHandler.Handle().ServeHTTP(rr, req) require.Equal(t, http.StatusBadRequest, rr.Code) - require.Equal(t, rr.Body.String(), "missing URI information") + require.Equal(t, rr.Body.String(), "missing profile name") }) t.Run("create profile error by passing invalid request", func(t *testing.T) { req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, bytes.NewBuffer([]byte(""))) @@ -265,17 +283,6 @@ func TestCreateProfileHandler(t *testing.T) { require.Equal(t, http.StatusBadRequest, rr.Code) require.Equal(t, rr.Body.String(), "Failed to write response for invalid request received") }) - t.Run("create profile error by internal create profile failure", func(t *testing.T) { - req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, - bytes.NewBuffer([]byte(testIncorrectIssuerProfile))) - require.NoError(t, err) - rr := httptest.NewRecorder() - - createProfileHandler.Handle().ServeHTTP(rr, req) - require.Equal(t, http.StatusBadRequest, rr.Code) - require.Contains(t, rr.Body.String(), "failed to parse the uri: parse &&%^)$: invalid URL escape") - }) - t.Run("create profile error unable to write a response while reading the request", func(t *testing.T) { req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, bytes.NewBuffer([]byte(""))) require.NoError(t, err) @@ -330,14 +337,14 @@ func TestGetProfileHandler(t *testing.T) { profile := createProfileSuccess(t, op) r, err := http.NewRequest(http.MethodGet, - "/profile/"+profile.ID, + "/profile/"+profile.Name, bytes.NewBuffer([]byte(""))) require.NoError(t, err) rr := httptest.NewRecorder() urlVars := make(map[string]string) - urlVars[profilePathVariable] = profile.ID + urlVars[profilePathVariable] = profile.Name req = mux.SetURLVars(r, urlVars) getProfileHandler.Handle().ServeHTTP(rr, req) @@ -346,7 +353,7 @@ func TestGetProfileHandler(t *testing.T) { profileResponse := &ProfileResponse{} err = json.Unmarshal(rr.Body.Bytes(), profileResponse) require.NoError(t, err) - require.Equal(t, profileResponse.ID, profile.ID) + require.Equal(t, profileResponse.Name, profile.Name) require.Equal(t, profileResponse.URI, profile.URI) }) t.Run("get profile error, bad request", func(t *testing.T) { @@ -375,25 +382,11 @@ func createProfileSuccess(t *testing.T, op *Operation) *ProfileResponse { require.NoError(t, err) require.Equal(t, http.StatusCreated, rr.Code) - require.NotEmpty(t, profile.ID) + require.NotEmpty(t, profile.Name) return profile } -func TestOperation_parseAndGetURL(t *testing.T) { - t.Run("parse uri success", func(t *testing.T) { - resp, err := parseAndGetURI("http://example.edu/credentials") - require.NotNil(t, resp) - require.NoError(t, err) - }) - t.Run("parse uri failed", func(t *testing.T) { - resp, err := parseAndGetURI("//not-valid.&&%^)$") - require.Empty(t, resp) - require.Error(t, err) - require.Contains(t, err.Error(), "failed to parse the uri") - }) -} - func TestCreate(t *testing.T) { b := mockResponseWriter{} op, err := New(memstore.NewProvider()) @@ -410,6 +403,65 @@ func TestCreate(t *testing.T) { require.Contains(t, logContents.String(), "Unable to send error response, response writer failed") } +func TestOperation_validateProfileRequest(t *testing.T) { + t.Run("valid profile ", func(t *testing.T) { + profile := getProfileRequest() + err := validateProfileRequest(profile) + require.NoError(t, err) + }) + t.Run("missing profile name", func(t *testing.T) { + profile := getProfileRequest() + profile.Name = "" + err := validateProfileRequest(profile) + require.Error(t, err) + require.Contains(t, err.Error(), "missing profile name") + }) + t.Run("missing DID", func(t *testing.T) { + profile := getProfileRequest() + profile.DID = "" + err := validateProfileRequest(profile) + require.Error(t, err) + require.Contains(t, err.Error(), "missing DID information") + }) + t.Run("missing URI ", func(t *testing.T) { + profile := getProfileRequest() + profile.URI = "" + err := validateProfileRequest(profile) + require.Error(t, err) + require.Contains(t, err.Error(), "missing URI information") + }) + t.Run("missing creator ", func(t *testing.T) { + profile := getProfileRequest() + profile.Creator = "" + err := validateProfileRequest(profile) + require.Error(t, err) + require.Contains(t, err.Error(), "missing creator") + }) + t.Run("missing signature type ", func(t *testing.T) { + profile := getProfileRequest() + profile.SignatureType = "" + err := validateProfileRequest(profile) + require.Error(t, err) + require.Contains(t, err.Error(), "missing signature type") + }) + t.Run("parse uri failed", func(t *testing.T) { + profile := getProfileRequest() + profile.URI = "//not-valid.&&%^)$" + err := validateProfileRequest(profile) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid uri") + }) +} + +func getProfileRequest() *ProfileRequest { + return &ProfileRequest{ + Name: "issuer", + DID: "did:method:abc", + URI: "http://example.com/credentials", + Creator: "did:method:abc#key2", + SignatureType: "Ed25519Signature2018"} +} + func getHandler(t *testing.T, op *Operation, lookup string) Handler { return getHandlerWithError(t, op, lookup) } @@ -433,6 +485,16 @@ func handlerLookup(t *testing.T, op *Operation, lookup string) Handler { return nil } +func getTestProfile() *ProfileResponse { + return &ProfileResponse{ + Name: "test", + DID: "did:test:abc", + URI: "https://test.com/credentials", + SignatureType: "Ed25519Signature2018", + Creator: "did:test:abc#key1", + } +} + type mockResponseWriter struct { } diff --git a/pkg/restapi/vc/operation/profile.go b/pkg/restapi/vc/operation/profile.go index 058b20852..ddbf30b6e 100644 --- a/pkg/restapi/vc/operation/profile.go +++ b/pkg/restapi/vc/operation/profile.go @@ -29,7 +29,7 @@ type Profile struct { // SaveProfile saves issuer profile to underlying store func (c *Profile) SaveProfile(profileResponse *ProfileResponse) error { - k := fmt.Sprintf(keyPattern, profileKeyPrefix, profileResponse.ID) + k := fmt.Sprintf(keyPattern, profileKeyPrefix, profileResponse.Name) bytes, err := json.Marshal(profileResponse) if err != nil { @@ -39,10 +39,9 @@ func (c *Profile) SaveProfile(profileResponse *ProfileResponse) error { return c.store.Put(k, bytes) } -// GetProfile returns profile id for given key from underlying store and -// stores the result in the value pointed to by v -func (c *Profile) GetProfile(id string) (*ProfileResponse, error) { - k := fmt.Sprintf(keyPattern, profileKeyPrefix, id) +// GetProfile returns profile information for given profile name from underlying store +func (c *Profile) GetProfile(name string) (*ProfileResponse, error) { + k := fmt.Sprintf(keyPattern, profileKeyPrefix, name) bytes, err := c.store.Get(k) if err != nil { diff --git a/pkg/restapi/vc/operation/profile_test.go b/pkg/restapi/vc/operation/profile_test.go index aee29f92c..2f8e065e0 100644 --- a/pkg/restapi/vc/operation/profile_test.go +++ b/pkg/restapi/vc/operation/profile_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - "github.com/google/uuid" "github.com/stretchr/testify/require" mockstorage "github.com/trustbloc/edge-core/pkg/storage/mockstore" @@ -24,7 +23,7 @@ func TestCredentialRecord_SaveProfile(t *testing.T) { issueDate := time.Now().UTC() value := &ProfileResponse{ - ID: uuid.New().String(), + Name: "issuer", URI: "https://example.com/credentials/1872", IssueDate: &issueDate, } @@ -33,7 +32,7 @@ func TestCredentialRecord_SaveProfile(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, store) - k := fmt.Sprintf(keyPattern, profileKeyPrefix, value.ID) + k := fmt.Sprintf(keyPattern, profileKeyPrefix, value.Name) v, err := record.store.Get(k) require.NoError(t, err) require.NotEmpty(t, v) @@ -48,8 +47,8 @@ func TestCredentialRecord_GetProfile(t *testing.T) { issueDate := time.Now().UTC() valueStored := &ProfileResponse{ - ID: uuid.New().String(), - URI: "https://example.com/credentials/1872", + Name: "issuer", + URI: "https://example.com/credentials", IssueDate: &issueDate, } @@ -58,7 +57,7 @@ func TestCredentialRecord_GetProfile(t *testing.T) { require.NotEmpty(t, store) - valueFound, err := record.GetProfile(valueStored.ID) + valueFound, err := record.GetProfile(valueStored.Name) require.NoError(t, err) require.Equal(t, valueStored, valueFound) })