diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 63bd9d07be7a5962517b0fb2c33b24d714822c09..b2048c1984351b48488ecf0ae152a0e9b6558eaa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,7 +16,7 @@ include: - template: 'Workflows/Branch-Pipelines.gitlab-ci.yml' lint: - image: golangci/golangci-lint:v1.44.2 + image: golangci/golangci-lint:v1.50.1 stage: test tags: - amd64-docker @@ -28,12 +28,27 @@ lint: - cd /go/src/gitlab.com/${CI_PROJECT_PATH} unit tests: - image: golang:1.17.7 + image: golang:1.19.3 extends: .gotest stage: test tags: - amd64-docker before_script: [] + coverage: '/total:\s+\(statements\)\s+(\d+.\d+\%)/' + +govulncheck: + image: golang:1.19.3 + stage: test + tags: + - amd64-docker + before_script: + - ln -s /builds /go/src/gitlab.com + - cd /go/src/gitlab.com/${CI_PROJECT_PATH} + script: + - go version + - go install golang.org/x/vuln/cmd/govulncheck@latest + - govulncheck ./... + amd64: extends: .docker-build diff --git a/.golangci.yml b/.golangci.yml index e6ba71d0fff71ba18fa18f4bd0f55fbaad679ab2..a31b66b24000f23ec82f765c828a26cf2bef07bd 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -12,7 +12,6 @@ linters: enable: - megacheck - govet - - deadcode - errcheck - goconst - gocyclo @@ -22,10 +21,9 @@ linters: - ineffassign - nakedret - staticcheck - - structcheck - unconvert - - varcheck - vet - vetshadow - misspell - staticcheck + - unused diff --git a/cmd/infohub/main.go b/cmd/infohub/main.go index 528254cf4f2f73c582ebd5a154cc74e66ba260b6..138bf4b4048dca2abf3a4e207b1f53deb9b3b27c 100644 --- a/cmd/infohub/main.go +++ b/cmd/infohub/main.go @@ -239,7 +239,7 @@ func exposeMetrics(addr string, logger *zap.Logger) { promMux := http.NewServeMux() promMux.Handle("/metrics", promhttp.Handler()) logger.Info(fmt.Sprintf("exposing prometheus metrics at %s/metrics", addr)) - if err := http.ListenAndServe(addr, promMux); err != nil { + if err := http.ListenAndServe(addr, promMux); err != nil { //nolint:gosec logger.Error("error exposing prometheus metrics", zap.Error(err)) } } diff --git a/deployment/ci/Dockerfile b/deployment/ci/Dockerfile index f216cd5e2b25e435f20d4dab62067745c42a64c4..0a90d092da2c9ed30a876e3a60458d037c0280ad 100644 --- a/deployment/ci/Dockerfile +++ b/deployment/ci/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.19-alpine3.15 as builder +FROM golang:1.19.3-alpine3.15 as builder RUN apk add git diff --git a/deployment/compose/Dockerfile b/deployment/compose/Dockerfile index 2bc21f6f0019826613955241677f8c091c70d933..6e4ef22aac6a1bde7022d47c3fe69c67e96ca345 100644 --- a/deployment/compose/Dockerfile +++ b/deployment/compose/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.19 +FROM golang:1.19.3 ENV GO111MODULE=on diff --git a/internal/clients/signer/client.go b/internal/clients/signer/client.go index c75c5064004f550d8db50b266481ce0b3a5bd25e..1550511dcf6763b6e76670a14fb9ad6aef2d8843 100644 --- a/internal/clients/signer/client.go +++ b/internal/clients/signer/client.go @@ -4,19 +4,16 @@ import ( "bytes" "context" "encoding/json" - "fmt" "io" - "io/ioutil" "net/http" - "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" "github.com/piprate/json-gold/ld" "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors" ) const ( - presentationProofPath = "/v1/presentation/proof" + createPresentationPath = "/v1/presentation" presentationVerifyPath = "/v1/presentation/verify" ) @@ -41,13 +38,20 @@ func New(addr string, opts ...ClientOption) *Client { return c } -func (c *Client) PresentationProof(ctx context.Context, vp *verifiable.Presentation) (*verifiable.Presentation, error) { - vpBytes, err := json.Marshal(vp) +func (c *Client) CreatePresentation(ctx context.Context, issuer, namespace, key string, data []map[string]interface{}) (map[string]interface{}, error) { + payload := map[string]interface{}{ + "issuer": issuer, + "namespace": namespace, + "key": key, + "data": data, + } + + payloadJSON, err := json.Marshal(payload) if err != nil { return nil, err } - req, err := http.NewRequestWithContext(ctx, "POST", c.addr+presentationProofPath, bytes.NewReader(vpBytes)) + req, err := http.NewRequestWithContext(ctx, "POST", c.addr+createPresentationPath, bytes.NewReader(payloadJSON)) if err != nil { return nil, err } @@ -59,19 +63,15 @@ func (c *Client) PresentationProof(ctx context.Context, vp *verifiable.Presentat defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("unexpected response from signer: %s", resp.Status) + return nil, errors.New(errors.GetKind(resp.StatusCode), getErrorBody(resp)) } - respBytes, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err + var presentation map[string]interface{} + if err := json.NewDecoder(resp.Body).Decode(&presentation); err != nil { + return nil, errors.New("error decoding signer response as verifiable presentation", err) } - return verifiable.ParsePresentation( - respBytes, - verifiable.WithPresJSONLDDocumentLoader(c.docLoader), - verifiable.WithPresDisabledProofCheck(), - ) + return presentation, nil } func (c *Client) VerifyPresentation(ctx context.Context, vp []byte) error { @@ -105,7 +105,7 @@ func (c *Client) VerifyPresentation(ctx context.Context, vp []byte) error { } func getErrorBody(resp *http.Response) string { - body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 2<<20)) + body, err := io.ReadAll(io.LimitReader(resp.Body, 2<<20)) if err != nil { return "" } diff --git a/internal/clients/signer/client_test.go b/internal/clients/signer/client_test.go index 2ea0ca6559d2da63aa312215ce3c040ac162bb69..065ce82afbc585508495b2f4bc7695ac48ab2c64 100644 --- a/internal/clients/signer/client_test.go +++ b/internal/clients/signer/client_test.go @@ -6,125 +6,107 @@ import ( "net/http/httptest" "testing" - "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" - "github.com/piprate/json-gold/ld" "github.com/stretchr/testify/assert" + "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors" "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/infohub/internal/clients/signer" ) -const invalidPresentation = `{"invalid":"verifiable_presentation"}` - -const validPresentation = `{ - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://www.w3.org/2018/credentials/examples/v1" - ], - "id": "did:123", - "type": "VerifiablePresentation", - "verifiableCredential": [ - { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://www.w3.org/2018/credentials/examples/v1" - ], - "credentialSubject": { - "allow": true, - "id": "example/example/1.0", - "taskID": "0123456789abcdef" - }, - "issuanceDate": "2022-06-14T08:43:22.78309334Z", - "issuer": "https://example.com", - "type": "VerifiableCredential" - }, - { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://www.w3.org/2018/credentials/examples/v1" - ], - "credentialSubject": { - "id": "example/example/2.0", - "result": { - "hello": "world" - } - }, - "issuanceDate": "2022-06-14T08:43:22.783102173Z", - "issuer": "https://example.com", - "type": "VerifiableCredential" - } - ] -}` - -func TestClient_PresentationProof(t *testing.T) { +func TestClient_CreatePresentation(t *testing.T) { tests := []struct { name string - ctx context.Context - vp *verifiable.Presentation + data []map[string]interface{} handler http.HandlerFunc - result *verifiable.Presentation + result map[string]interface{} + errkind errors.Kind errtext string }{ { - name: "error creating http request because of nil context", - errtext: "net/http: nil Context", + name: "signer returns error", + data: []map[string]interface{}{{"hello": "world"}}, + handler: func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte("some error")) + }, + errkind: errors.Internal, + errtext: "some error", }, { - name: "signer server returns unexpected response code", - ctx: context.Background(), + name: "signer successfully creates verifiable presentation", + data: []map[string]interface{}{{"hello": "world"}}, handler: func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusServiceUnavailable) + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"id":"did:web:example.com"}`)) }, - errtext: "unexpected response from signer: 503 Service Unavailable", + result: map[string]interface{}{"id": "did:web:example.com"}, }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + srv := httptest.NewServer(test.handler) + client := signer.New(srv.URL) + result, err := client.CreatePresentation(context.Background(), "issuer", "namespace", "key", test.data) + if test.errtext != "" { + assert.Error(t, err) + assert.Contains(t, err.Error(), test.errtext) + assert.Nil(t, result) + } else { + assert.NotNil(t, result) + assert.Equal(t, test.result, result) + } + }) + } +} + +func TestClient_VerifyPresentation(t *testing.T) { + tests := []struct { + name string + vp []byte + handler http.HandlerFunc + errkind errors.Kind + errtext string + }{ { - name: "signer server returns empty response", - ctx: context.Background(), + name: "signer returns error", + vp: []byte(`{"id":"did:web:example.com"}`), handler: func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte("some error")) }, - errtext: "JSON unmarshalling of verifiable presentation: unexpected end of JSON input", + errkind: errors.Internal, + errtext: "some error", }, { - name: "signer server returns invalid verifiable presentation", - ctx: context.Background(), + name: "signer returns unexpected response", + vp: []byte(`{"id":"did:web:example.com"}`), handler: func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(invalidPresentation)) + _, _ = w.Write([]byte("invalid json")) }, - errtext: "verifiable presentation is not valid", + errkind: errors.Unknown, + errtext: "failed to decode response", }, { - name: "signer server returns valid presentation", - ctx: context.Background(), + name: "signer returns successfully", + vp: []byte(`{"id":"did:web:example.com"}`), handler: func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(validPresentation)) + _, _ = w.Write([]byte(`{"id":"did:web:example.com"}`)) }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - signerSrv := httptest.NewServer(test.handler) - client := signer.New(signerSrv.URL, signer.WithHTTPClient(http.DefaultClient)) - result, err := client.PresentationProof(test.ctx, test.vp) + srv := httptest.NewServer(test.handler) + client := signer.New(srv.URL) + err := client.VerifyPresentation(context.Background(), test.vp) if err != nil { - assert.Nil(t, result) - assert.NotEmpty(t, test.errtext) assert.Contains(t, err.Error(), test.errtext) } else { assert.Empty(t, test.errtext) - assert.NotNil(t, result) - - // parse the string representation to compare with the returned result - vp, err := verifiable.ParsePresentation( - []byte(validPresentation), - verifiable.WithPresJSONLDDocumentLoader(ld.NewDefaultDocumentLoader(http.DefaultClient)), - verifiable.WithPresDisabledProofCheck(), - ) - assert.NoError(t, err) - assert.Equal(t, vp, result) } }) } diff --git a/internal/service/infohub/infohubfakes/fake_credentials.go b/internal/service/infohub/infohubfakes/fake_credentials.go index a66c24875dedb1748d9b4772f30693c332214397..783fab3ebd50afdbf915a4aa2d8d07d46e1bac91 100644 --- a/internal/service/infohub/infohubfakes/fake_credentials.go +++ b/internal/service/infohub/infohubfakes/fake_credentials.go @@ -9,36 +9,6 @@ import ( ) type FakeCredentials struct { - NewCredentialStub func([]string, string, map[string]interface{}, bool) (*verifiable.Credential, error) - newCredentialMutex sync.RWMutex - newCredentialArgsForCall []struct { - arg1 []string - arg2 string - arg3 map[string]interface{} - arg4 bool - } - newCredentialReturns struct { - result1 *verifiable.Credential - result2 error - } - newCredentialReturnsOnCall map[int]struct { - result1 *verifiable.Credential - result2 error - } - NewPresentationStub func([]string, ...*verifiable.Credential) (*verifiable.Presentation, error) - newPresentationMutex sync.RWMutex - newPresentationArgsForCall []struct { - arg1 []string - arg2 []*verifiable.Credential - } - newPresentationReturns struct { - result1 *verifiable.Presentation - result2 error - } - newPresentationReturnsOnCall map[int]struct { - result1 *verifiable.Presentation - result2 error - } ParsePresentationStub func([]byte) (*verifiable.Presentation, error) parsePresentationMutex sync.RWMutex parsePresentationArgsForCall []struct { @@ -56,148 +26,6 @@ type FakeCredentials struct { invocationsMutex sync.RWMutex } -func (fake *FakeCredentials) NewCredential(arg1 []string, arg2 string, arg3 map[string]interface{}, arg4 bool) (*verifiable.Credential, error) { - var arg1Copy []string - if arg1 != nil { - arg1Copy = make([]string, len(arg1)) - copy(arg1Copy, arg1) - } - fake.newCredentialMutex.Lock() - ret, specificReturn := fake.newCredentialReturnsOnCall[len(fake.newCredentialArgsForCall)] - fake.newCredentialArgsForCall = append(fake.newCredentialArgsForCall, struct { - arg1 []string - arg2 string - arg3 map[string]interface{} - arg4 bool - }{arg1Copy, arg2, arg3, arg4}) - stub := fake.NewCredentialStub - fakeReturns := fake.newCredentialReturns - fake.recordInvocation("NewCredential", []interface{}{arg1Copy, arg2, arg3, arg4}) - fake.newCredentialMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3, arg4) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *FakeCredentials) NewCredentialCallCount() int { - fake.newCredentialMutex.RLock() - defer fake.newCredentialMutex.RUnlock() - return len(fake.newCredentialArgsForCall) -} - -func (fake *FakeCredentials) NewCredentialCalls(stub func([]string, string, map[string]interface{}, bool) (*verifiable.Credential, error)) { - fake.newCredentialMutex.Lock() - defer fake.newCredentialMutex.Unlock() - fake.NewCredentialStub = stub -} - -func (fake *FakeCredentials) NewCredentialArgsForCall(i int) ([]string, string, map[string]interface{}, bool) { - fake.newCredentialMutex.RLock() - defer fake.newCredentialMutex.RUnlock() - argsForCall := fake.newCredentialArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 -} - -func (fake *FakeCredentials) NewCredentialReturns(result1 *verifiable.Credential, result2 error) { - fake.newCredentialMutex.Lock() - defer fake.newCredentialMutex.Unlock() - fake.NewCredentialStub = nil - fake.newCredentialReturns = struct { - result1 *verifiable.Credential - result2 error - }{result1, result2} -} - -func (fake *FakeCredentials) NewCredentialReturnsOnCall(i int, result1 *verifiable.Credential, result2 error) { - fake.newCredentialMutex.Lock() - defer fake.newCredentialMutex.Unlock() - fake.NewCredentialStub = nil - if fake.newCredentialReturnsOnCall == nil { - fake.newCredentialReturnsOnCall = make(map[int]struct { - result1 *verifiable.Credential - result2 error - }) - } - fake.newCredentialReturnsOnCall[i] = struct { - result1 *verifiable.Credential - result2 error - }{result1, result2} -} - -func (fake *FakeCredentials) NewPresentation(arg1 []string, arg2 ...*verifiable.Credential) (*verifiable.Presentation, error) { - var arg1Copy []string - if arg1 != nil { - arg1Copy = make([]string, len(arg1)) - copy(arg1Copy, arg1) - } - fake.newPresentationMutex.Lock() - ret, specificReturn := fake.newPresentationReturnsOnCall[len(fake.newPresentationArgsForCall)] - fake.newPresentationArgsForCall = append(fake.newPresentationArgsForCall, struct { - arg1 []string - arg2 []*verifiable.Credential - }{arg1Copy, arg2}) - stub := fake.NewPresentationStub - fakeReturns := fake.newPresentationReturns - fake.recordInvocation("NewPresentation", []interface{}{arg1Copy, arg2}) - fake.newPresentationMutex.Unlock() - if stub != nil { - return stub(arg1, arg2...) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *FakeCredentials) NewPresentationCallCount() int { - fake.newPresentationMutex.RLock() - defer fake.newPresentationMutex.RUnlock() - return len(fake.newPresentationArgsForCall) -} - -func (fake *FakeCredentials) NewPresentationCalls(stub func([]string, ...*verifiable.Credential) (*verifiable.Presentation, error)) { - fake.newPresentationMutex.Lock() - defer fake.newPresentationMutex.Unlock() - fake.NewPresentationStub = stub -} - -func (fake *FakeCredentials) NewPresentationArgsForCall(i int) ([]string, []*verifiable.Credential) { - fake.newPresentationMutex.RLock() - defer fake.newPresentationMutex.RUnlock() - argsForCall := fake.newPresentationArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *FakeCredentials) NewPresentationReturns(result1 *verifiable.Presentation, result2 error) { - fake.newPresentationMutex.Lock() - defer fake.newPresentationMutex.Unlock() - fake.NewPresentationStub = nil - fake.newPresentationReturns = struct { - result1 *verifiable.Presentation - result2 error - }{result1, result2} -} - -func (fake *FakeCredentials) NewPresentationReturnsOnCall(i int, result1 *verifiable.Presentation, result2 error) { - fake.newPresentationMutex.Lock() - defer fake.newPresentationMutex.Unlock() - fake.NewPresentationStub = nil - if fake.newPresentationReturnsOnCall == nil { - fake.newPresentationReturnsOnCall = make(map[int]struct { - result1 *verifiable.Presentation - result2 error - }) - } - fake.newPresentationReturnsOnCall[i] = struct { - result1 *verifiable.Presentation - result2 error - }{result1, result2} -} - func (fake *FakeCredentials) ParsePresentation(arg1 []byte) (*verifiable.Presentation, error) { var arg1Copy []byte if arg1 != nil { @@ -270,10 +98,6 @@ func (fake *FakeCredentials) ParsePresentationReturnsOnCall(i int, result1 *veri func (fake *FakeCredentials) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() - fake.newCredentialMutex.RLock() - defer fake.newCredentialMutex.RUnlock() - fake.newPresentationMutex.RLock() - defer fake.newPresentationMutex.RUnlock() fake.parsePresentationMutex.RLock() defer fake.parsePresentationMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} diff --git a/internal/service/infohub/infohubfakes/fake_signer.go b/internal/service/infohub/infohubfakes/fake_signer.go index db2c0e1e4937a7162d9e6b180f833fefcf5e5712..556e6de1a5e261d52a65c07667c00b0145d31b30 100644 --- a/internal/service/infohub/infohubfakes/fake_signer.go +++ b/internal/service/infohub/infohubfakes/fake_signer.go @@ -5,23 +5,25 @@ import ( "context" "sync" - "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/infohub/internal/service/infohub" ) type FakeSigner struct { - PresentationProofStub func(context.Context, *verifiable.Presentation) (*verifiable.Presentation, error) - presentationProofMutex sync.RWMutex - presentationProofArgsForCall []struct { + CreatePresentationStub func(context.Context, string, string, string, []map[string]interface{}) (map[string]interface{}, error) + createPresentationMutex sync.RWMutex + createPresentationArgsForCall []struct { arg1 context.Context - arg2 *verifiable.Presentation + arg2 string + arg3 string + arg4 string + arg5 []map[string]interface{} } - presentationProofReturns struct { - result1 *verifiable.Presentation + createPresentationReturns struct { + result1 map[string]interface{} result2 error } - presentationProofReturnsOnCall map[int]struct { - result1 *verifiable.Presentation + createPresentationReturnsOnCall map[int]struct { + result1 map[string]interface{} result2 error } VerifyPresentationStub func(context.Context, []byte) error @@ -40,19 +42,27 @@ type FakeSigner struct { invocationsMutex sync.RWMutex } -func (fake *FakeSigner) PresentationProof(arg1 context.Context, arg2 *verifiable.Presentation) (*verifiable.Presentation, error) { - fake.presentationProofMutex.Lock() - ret, specificReturn := fake.presentationProofReturnsOnCall[len(fake.presentationProofArgsForCall)] - fake.presentationProofArgsForCall = append(fake.presentationProofArgsForCall, struct { +func (fake *FakeSigner) CreatePresentation(arg1 context.Context, arg2 string, arg3 string, arg4 string, arg5 []map[string]interface{}) (map[string]interface{}, error) { + var arg5Copy []map[string]interface{} + if arg5 != nil { + arg5Copy = make([]map[string]interface{}, len(arg5)) + copy(arg5Copy, arg5) + } + fake.createPresentationMutex.Lock() + ret, specificReturn := fake.createPresentationReturnsOnCall[len(fake.createPresentationArgsForCall)] + fake.createPresentationArgsForCall = append(fake.createPresentationArgsForCall, struct { arg1 context.Context - arg2 *verifiable.Presentation - }{arg1, arg2}) - stub := fake.PresentationProofStub - fakeReturns := fake.presentationProofReturns - fake.recordInvocation("PresentationProof", []interface{}{arg1, arg2}) - fake.presentationProofMutex.Unlock() + arg2 string + arg3 string + arg4 string + arg5 []map[string]interface{} + }{arg1, arg2, arg3, arg4, arg5Copy}) + stub := fake.CreatePresentationStub + fakeReturns := fake.createPresentationReturns + fake.recordInvocation("CreatePresentation", []interface{}{arg1, arg2, arg3, arg4, arg5Copy}) + fake.createPresentationMutex.Unlock() if stub != nil { - return stub(arg1, arg2) + return stub(arg1, arg2, arg3, arg4, arg5) } if specificReturn { return ret.result1, ret.result2 @@ -60,47 +70,47 @@ func (fake *FakeSigner) PresentationProof(arg1 context.Context, arg2 *verifiable return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeSigner) PresentationProofCallCount() int { - fake.presentationProofMutex.RLock() - defer fake.presentationProofMutex.RUnlock() - return len(fake.presentationProofArgsForCall) +func (fake *FakeSigner) CreatePresentationCallCount() int { + fake.createPresentationMutex.RLock() + defer fake.createPresentationMutex.RUnlock() + return len(fake.createPresentationArgsForCall) } -func (fake *FakeSigner) PresentationProofCalls(stub func(context.Context, *verifiable.Presentation) (*verifiable.Presentation, error)) { - fake.presentationProofMutex.Lock() - defer fake.presentationProofMutex.Unlock() - fake.PresentationProofStub = stub +func (fake *FakeSigner) CreatePresentationCalls(stub func(context.Context, string, string, string, []map[string]interface{}) (map[string]interface{}, error)) { + fake.createPresentationMutex.Lock() + defer fake.createPresentationMutex.Unlock() + fake.CreatePresentationStub = stub } -func (fake *FakeSigner) PresentationProofArgsForCall(i int) (context.Context, *verifiable.Presentation) { - fake.presentationProofMutex.RLock() - defer fake.presentationProofMutex.RUnlock() - argsForCall := fake.presentationProofArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 +func (fake *FakeSigner) CreatePresentationArgsForCall(i int) (context.Context, string, string, string, []map[string]interface{}) { + fake.createPresentationMutex.RLock() + defer fake.createPresentationMutex.RUnlock() + argsForCall := fake.createPresentationArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5 } -func (fake *FakeSigner) PresentationProofReturns(result1 *verifiable.Presentation, result2 error) { - fake.presentationProofMutex.Lock() - defer fake.presentationProofMutex.Unlock() - fake.PresentationProofStub = nil - fake.presentationProofReturns = struct { - result1 *verifiable.Presentation +func (fake *FakeSigner) CreatePresentationReturns(result1 map[string]interface{}, result2 error) { + fake.createPresentationMutex.Lock() + defer fake.createPresentationMutex.Unlock() + fake.CreatePresentationStub = nil + fake.createPresentationReturns = struct { + result1 map[string]interface{} result2 error }{result1, result2} } -func (fake *FakeSigner) PresentationProofReturnsOnCall(i int, result1 *verifiable.Presentation, result2 error) { - fake.presentationProofMutex.Lock() - defer fake.presentationProofMutex.Unlock() - fake.PresentationProofStub = nil - if fake.presentationProofReturnsOnCall == nil { - fake.presentationProofReturnsOnCall = make(map[int]struct { - result1 *verifiable.Presentation +func (fake *FakeSigner) CreatePresentationReturnsOnCall(i int, result1 map[string]interface{}, result2 error) { + fake.createPresentationMutex.Lock() + defer fake.createPresentationMutex.Unlock() + fake.CreatePresentationStub = nil + if fake.createPresentationReturnsOnCall == nil { + fake.createPresentationReturnsOnCall = make(map[int]struct { + result1 map[string]interface{} result2 error }) } - fake.presentationProofReturnsOnCall[i] = struct { - result1 *verifiable.Presentation + fake.createPresentationReturnsOnCall[i] = struct { + result1 map[string]interface{} result2 error }{result1, result2} } @@ -175,8 +185,8 @@ func (fake *FakeSigner) VerifyPresentationReturnsOnCall(i int, result1 error) { func (fake *FakeSigner) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() - fake.presentationProofMutex.RLock() - defer fake.presentationProofMutex.RUnlock() + fake.createPresentationMutex.RLock() + defer fake.createPresentationMutex.RUnlock() fake.verifyPresentationMutex.RLock() defer fake.verifyPresentationMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} diff --git a/internal/service/infohub/service.go b/internal/service/infohub/service.go index be44fc97cdec3da754f3c19bb049d41726858a71..56149b5457fe02a7d951250819694e80461aa90f 100644 --- a/internal/service/infohub/service.go +++ b/internal/service/infohub/service.go @@ -35,13 +35,11 @@ type Cache interface { } type Credentials interface { - NewCredential(contexts []string, subjectID string, subject map[string]interface{}, proof bool) (*verifiable.Credential, error) - NewPresentation(contexts []string, credentials ...*verifiable.Credential) (*verifiable.Presentation, error) ParsePresentation(vpBytes []byte) (*verifiable.Presentation, error) } type Signer interface { - PresentationProof(ctx context.Context, vp *verifiable.Presentation) (*verifiable.Presentation, error) + CreatePresentation(ctx context.Context, issuer, namespace, key string, data []map[string]interface{}) (map[string]interface{}, error) VerifyPresentation(ctx context.Context, vp []byte) error } @@ -150,35 +148,26 @@ func (s *Service) Export(ctx context.Context, req *infohub.ExportRequest) (inter return nil, err } - // wrap each policy result in a verifiable credential - var creds []*verifiable.Credential + var results []map[string]interface{} for policy, result := range policyResults { var res map[string]interface{} if err := json.Unmarshal(result, &res); err != nil { - logger.Error("error decoding policy result as json", zap.Error(err)) + logger.Error("error decoding policy result as json", zap.Error(err), zap.String("policy", policy)) return nil, errors.New("error creating export", err) } - - // credentials do not include proof, because the final VP will include a proof for all - cred, err := s.credentials.NewCredential(exportCfg.Contexts, policy, res, false) - if err != nil { - logger.Error("failed to create verifiable credential", zap.Error(err)) - return nil, errors.New("error creating export", err) - } - creds = append(creds, cred) + results = append(results, res) } - // wrap all credentials in a verifiable presentation - vp, err := s.credentials.NewPresentation(exportCfg.Contexts, creds...) - if err != nil { - logger.Error("failed to create verifiable presentation", zap.Error(err)) - return nil, errors.New("error creating export", err) - } - - // get presentation proof from the signer - vp, err = s.signer.PresentationProof(ctx, vp) + // create verifiable presentation + vp, err := s.signer.CreatePresentation( + ctx, + exportCfg.Issuer, + exportCfg.KeyNamespace, + exportCfg.Key, + results, + ) if err != nil { - logger.Error("fail to get presentation proof", zap.Error(err)) + logger.Error("error creating verifiable presentation", zap.Error(err)) return nil, errors.New("error creating export", err) } @@ -190,6 +179,8 @@ func (s *Service) Export(ctx context.Context, req *infohub.ExportRequest) (inter // is returned. // If all results are found, they are returned as map, where the key is policyName // and the value is the JSON serialized bytes of the policy result. +// +// policyNames are formatted as 'group/policy/version' string, e.g. 'example/example/1.0' func (s *Service) getExportData(ctx context.Context, exportName string, policyNames []string) (map[string][]byte, error) { results := make(map[string][]byte) for _, policy := range policyNames { diff --git a/internal/service/infohub/service_test.go b/internal/service/infohub/service_test.go index c585ea29797dd4d57b2bfa3c644085b5b16db801..b9ad07862eef5c60930c2e30b407cee59bf06b05 100644 --- a/internal/service/infohub/service_test.go +++ b/internal/service/infohub/service_test.go @@ -4,7 +4,6 @@ import ( "context" "testing" - "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" "github.com/stretchr/testify/assert" "go.uber.org/zap" @@ -173,7 +172,7 @@ func TestService_Export(t *testing.T) { errtext: "error creating export: invalid character", }, { - name: "error creating verifiable credential for data", + name: "error creating verifiable presentation", req: &goasigner.ExportRequest{ExportName: "testexport"}, storage: &infohubfakes.FakeStorage{ ExportConfigurationStub: func(ctx context.Context, s string) (*storage.ExportConfiguration, error) { @@ -189,77 +188,16 @@ func TestService_Export(t *testing.T) { return []byte(`{"allow":true}`), nil }, }, - cred: &infohubfakes.FakeCredentials{ - NewCredentialStub: func(contexts []string, policy string, data map[string]interface{}, proof bool) (*verifiable.Credential, error) { - return nil, errors.New("cannot create credential") - }, - }, - errkind: errors.Unknown, - errtext: "cannot create credential", - }, - { - name: "error creating verifiable presentation for data", - req: &goasigner.ExportRequest{ExportName: "testexport"}, - storage: &infohubfakes.FakeStorage{ - ExportConfigurationStub: func(ctx context.Context, s string) (*storage.ExportConfiguration, error) { - return &storage.ExportConfiguration{ - ExportName: "testexport", - Contexts: []string{"https://www.w3.org/2018/credentials/examples/v1"}, - Policies: map[string]interface{}{"test/test/1.0": map[string]interface{}{"hello": "test world"}}, - }, nil - }, - }, - cache: &infohubfakes.FakeCache{ - GetStub: func(ctx context.Context, key string, namespace string, scope string) ([]byte, error) { - return []byte(`{"allow":true}`), nil - }, - }, - cred: &infohubfakes.FakeCredentials{ - NewCredentialStub: func(contexts []string, policy string, data map[string]interface{}, proof bool) (*verifiable.Credential, error) { - return &verifiable.Credential{}, nil - }, - NewPresentationStub: func(contexts []string, credentials ...*verifiable.Credential) (*verifiable.Presentation, error) { - return nil, errors.New("cannot create presentation") - }, - }, - errkind: errors.Unknown, - errtext: "cannot create presentation", - }, - { - name: "error getting verifiable presentation proof", - req: &goasigner.ExportRequest{ExportName: "testexport"}, - storage: &infohubfakes.FakeStorage{ - ExportConfigurationStub: func(ctx context.Context, s string) (*storage.ExportConfiguration, error) { - return &storage.ExportConfiguration{ - ExportName: "testexport", - Contexts: []string{"https://www.w3.org/2018/credentials/examples/v1"}, - Policies: map[string]interface{}{"test/test/1.0": map[string]interface{}{"hello": "test world"}}, - }, nil - }, - }, - cache: &infohubfakes.FakeCache{ - GetStub: func(ctx context.Context, key string, namespace string, scope string) ([]byte, error) { - return []byte(`{"allow":true}`), nil - }, - }, - cred: &infohubfakes.FakeCredentials{ - NewCredentialStub: func(contexts []string, policy string, data map[string]interface{}, proof bool) (*verifiable.Credential, error) { - return &verifiable.Credential{}, nil - }, - NewPresentationStub: func(contexts []string, credentials ...*verifiable.Credential) (*verifiable.Presentation, error) { - return &verifiable.Presentation{}, nil - }, - }, signer: &infohubfakes.FakeSigner{ - PresentationProofStub: func(ctx context.Context, presentation *verifiable.Presentation) (*verifiable.Presentation, error) { - return nil, errors.New(errors.ServiceUnavailable, "service unavailable") + CreatePresentationStub: func(ctx context.Context, issuer string, namespace string, key string, data []map[string]interface{}) (map[string]interface{}, error) { + return nil, errors.New("some error") }, }, - errkind: errors.ServiceUnavailable, - errtext: "service unavailable", + errkind: errors.Unknown, + errtext: "some error", }, { - name: "exported data is returned successfully", + name: "successfully create verifiable presentation", req: &goasigner.ExportRequest{ExportName: "testexport"}, storage: &infohubfakes.FakeStorage{ ExportConfigurationStub: func(ctx context.Context, s string) (*storage.ExportConfiguration, error) { @@ -275,20 +213,12 @@ func TestService_Export(t *testing.T) { return []byte(`{"allow":true}`), nil }, }, - cred: &infohubfakes.FakeCredentials{ - NewCredentialStub: func(contexts []string, policy string, data map[string]interface{}, proof bool) (*verifiable.Credential, error) { - return &verifiable.Credential{}, nil - }, - NewPresentationStub: func(contexts []string, credentials ...*verifiable.Credential) (*verifiable.Presentation, error) { - return &verifiable.Presentation{}, nil - }, - }, signer: &infohubfakes.FakeSigner{ - PresentationProofStub: func(ctx context.Context, presentation *verifiable.Presentation) (*verifiable.Presentation, error) { - return &verifiable.Presentation{ID: "did:ocm"}, nil + CreatePresentationStub: func(ctx context.Context, issuer string, namespace string, key string, data []map[string]interface{}) (map[string]interface{}, error) { + return map[string]interface{}{"id": "did:web:example.com"}, nil }, }, - res: &verifiable.Presentation{ID: "did:ocm"}, + res: map[string]interface{}{"id": "did:web:example.com"}, }, } diff --git a/internal/storage/storage.go b/internal/storage/storage.go index 5c6072c86f0ccafe31c50dd33ae993b2d9975fdc..c85b2af5a5faf87471ca880a7ee7a9d27a384247 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -12,10 +12,13 @@ import ( ) type ExportConfiguration struct { - ExportName string - Contexts []string - Policies map[string]interface{} - CacheTTL *int + ExportName string + Contexts []string + Policies map[string]interface{} + CacheTTL *int + Issuer string // issuer DID + KeyNamespace string // signing key namespace + Key string // signing key name } type Storage struct {