Skip to content
Snippets Groups Projects
Commit a5b40872 authored by Lyuben Penkovski's avatar Lyuben Penkovski
Browse files

Refactor export VP creation according to changes in the Signer

Before this change the infohub service created VP itself and just
used the signer for acquiring a VP proof. With the new Signer endpoint
which can create VP from raw JSON data, the complexity in the export
decreased, because the infohub must not create a VP itself - VP
creation and VP proofs are completely delegated to the Signer service.
parent 72b5987f
Branches
Tags
No related merge requests found
...@@ -4,18 +4,16 @@ import ( ...@@ -4,18 +4,16 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"net/http" "net/http"
"github.com/hyperledger/aries-framework-go/pkg/doc/verifiable"
"github.com/piprate/json-gold/ld" "github.com/piprate/json-gold/ld"
"gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors" "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors"
) )
const ( const (
presentationProofPath = "/v1/presentation/proof" createPresentationPath = "/v1/presentation"
presentationVerifyPath = "/v1/presentation/verify" presentationVerifyPath = "/v1/presentation/verify"
) )
...@@ -40,13 +38,20 @@ func New(addr string, opts ...ClientOption) *Client { ...@@ -40,13 +38,20 @@ func New(addr string, opts ...ClientOption) *Client {
return c return c
} }
func (c *Client) PresentationProof(ctx context.Context, vp *verifiable.Presentation) (*verifiable.Presentation, error) { func (c *Client) CreatePresentation(ctx context.Context, issuer, namespace, key string, data []map[string]interface{}) (map[string]interface{}, error) {
vpBytes, err := json.Marshal(vp) payload := map[string]interface{}{
"issuer": issuer,
"namespace": namespace,
"key": key,
"data": data,
}
payloadJSON, err := json.Marshal(payload)
if err != nil { if err != nil {
return nil, err 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 { if err != nil {
return nil, err return nil, err
} }
...@@ -58,19 +63,15 @@ func (c *Client) PresentationProof(ctx context.Context, vp *verifiable.Presentat ...@@ -58,19 +63,15 @@ func (c *Client) PresentationProof(ctx context.Context, vp *verifiable.Presentat
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { 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) var presentation map[string]interface{}
if err != nil { if err := json.NewDecoder(resp.Body).Decode(&presentation); err != nil {
return nil, err return nil, errors.New("error decoding signer response as verifiable presentation", err)
} }
return verifiable.ParsePresentation( return presentation, nil
respBytes,
verifiable.WithPresJSONLDDocumentLoader(c.docLoader),
verifiable.WithPresDisabledProofCheck(),
)
} }
func (c *Client) VerifyPresentation(ctx context.Context, vp []byte) error { func (c *Client) VerifyPresentation(ctx context.Context, vp []byte) error {
......
...@@ -6,125 +6,107 @@ import ( ...@@ -6,125 +6,107 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/hyperledger/aries-framework-go/pkg/doc/verifiable"
"github.com/piprate/json-gold/ld"
"github.com/stretchr/testify/assert" "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" "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/infohub/internal/clients/signer"
) )
const invalidPresentation = `{"invalid":"verifiable_presentation"}` func TestClient_CreatePresentation(t *testing.T) {
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) {
tests := []struct { tests := []struct {
name string name string
ctx context.Context data []map[string]interface{}
vp *verifiable.Presentation
handler http.HandlerFunc handler http.HandlerFunc
result *verifiable.Presentation result map[string]interface{}
errkind errors.Kind
errtext string errtext string
}{ }{
{ {
name: "error creating http request because of nil context", name: "signer returns error",
errtext: "net/http: nil Context", 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", name: "signer successfully creates verifiable presentation",
ctx: context.Background(), data: []map[string]interface{}{{"hello": "world"}},
handler: func(w http.ResponseWriter, r *http.Request) { 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", name: "signer returns error",
ctx: context.Background(), vp: []byte(`{"id":"did:web:example.com"}`),
handler: func(w http.ResponseWriter, r *http.Request) { 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", name: "signer returns unexpected response",
ctx: context.Background(), vp: []byte(`{"id":"did:web:example.com"}`),
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) 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", name: "signer returns successfully",
ctx: context.Background(), vp: []byte(`{"id":"did:web:example.com"}`),
handler: func(w http.ResponseWriter, r *http.Request) { handler: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(validPresentation)) _, _ = w.Write([]byte(`{"id":"did:web:example.com"}`))
}, },
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
signerSrv := httptest.NewServer(test.handler) srv := httptest.NewServer(test.handler)
client := signer.New(signerSrv.URL, signer.WithHTTPClient(http.DefaultClient)) client := signer.New(srv.URL)
result, err := client.PresentationProof(test.ctx, test.vp) err := client.VerifyPresentation(context.Background(), test.vp)
if err != nil { if err != nil {
assert.Nil(t, result)
assert.NotEmpty(t, test.errtext)
assert.Contains(t, err.Error(), test.errtext) assert.Contains(t, err.Error(), test.errtext)
} else { } else {
assert.Empty(t, test.errtext) 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)
} }
}) })
} }
......
...@@ -9,36 +9,6 @@ import ( ...@@ -9,36 +9,6 @@ import (
) )
type FakeCredentials struct { 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) ParsePresentationStub func([]byte) (*verifiable.Presentation, error)
parsePresentationMutex sync.RWMutex parsePresentationMutex sync.RWMutex
parsePresentationArgsForCall []struct { parsePresentationArgsForCall []struct {
...@@ -56,148 +26,6 @@ type FakeCredentials struct { ...@@ -56,148 +26,6 @@ type FakeCredentials struct {
invocationsMutex sync.RWMutex 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) { func (fake *FakeCredentials) ParsePresentation(arg1 []byte) (*verifiable.Presentation, error) {
var arg1Copy []byte var arg1Copy []byte
if arg1 != nil { if arg1 != nil {
...@@ -270,10 +98,6 @@ func (fake *FakeCredentials) ParsePresentationReturnsOnCall(i int, result1 *veri ...@@ -270,10 +98,6 @@ func (fake *FakeCredentials) ParsePresentationReturnsOnCall(i int, result1 *veri
func (fake *FakeCredentials) Invocations() map[string][][]interface{} { func (fake *FakeCredentials) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock() fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock() defer fake.invocationsMutex.RUnlock()
fake.newCredentialMutex.RLock()
defer fake.newCredentialMutex.RUnlock()
fake.newPresentationMutex.RLock()
defer fake.newPresentationMutex.RUnlock()
fake.parsePresentationMutex.RLock() fake.parsePresentationMutex.RLock()
defer fake.parsePresentationMutex.RUnlock() defer fake.parsePresentationMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{} copiedInvocations := map[string][][]interface{}{}
......
...@@ -5,23 +5,25 @@ import ( ...@@ -5,23 +5,25 @@ import (
"context" "context"
"sync" "sync"
"github.com/hyperledger/aries-framework-go/pkg/doc/verifiable"
"gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/infohub/internal/service/infohub" "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/infohub/internal/service/infohub"
) )
type FakeSigner struct { type FakeSigner struct {
PresentationProofStub func(context.Context, *verifiable.Presentation) (*verifiable.Presentation, error) CreatePresentationStub func(context.Context, string, string, string, []map[string]interface{}) (map[string]interface{}, error)
presentationProofMutex sync.RWMutex createPresentationMutex sync.RWMutex
presentationProofArgsForCall []struct { createPresentationArgsForCall []struct {
arg1 context.Context arg1 context.Context
arg2 *verifiable.Presentation arg2 string
arg3 string
arg4 string
arg5 []map[string]interface{}
} }
presentationProofReturns struct { createPresentationReturns struct {
result1 *verifiable.Presentation result1 map[string]interface{}
result2 error result2 error
} }
presentationProofReturnsOnCall map[int]struct { createPresentationReturnsOnCall map[int]struct {
result1 *verifiable.Presentation result1 map[string]interface{}
result2 error result2 error
} }
VerifyPresentationStub func(context.Context, []byte) error VerifyPresentationStub func(context.Context, []byte) error
...@@ -40,19 +42,27 @@ type FakeSigner struct { ...@@ -40,19 +42,27 @@ type FakeSigner struct {
invocationsMutex sync.RWMutex invocationsMutex sync.RWMutex
} }
func (fake *FakeSigner) PresentationProof(arg1 context.Context, arg2 *verifiable.Presentation) (*verifiable.Presentation, error) { func (fake *FakeSigner) CreatePresentation(arg1 context.Context, arg2 string, arg3 string, arg4 string, arg5 []map[string]interface{}) (map[string]interface{}, error) {
fake.presentationProofMutex.Lock() var arg5Copy []map[string]interface{}
ret, specificReturn := fake.presentationProofReturnsOnCall[len(fake.presentationProofArgsForCall)] if arg5 != nil {
fake.presentationProofArgsForCall = append(fake.presentationProofArgsForCall, struct { 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 arg1 context.Context
arg2 *verifiable.Presentation arg2 string
}{arg1, arg2}) arg3 string
stub := fake.PresentationProofStub arg4 string
fakeReturns := fake.presentationProofReturns arg5 []map[string]interface{}
fake.recordInvocation("PresentationProof", []interface{}{arg1, arg2}) }{arg1, arg2, arg3, arg4, arg5Copy})
fake.presentationProofMutex.Unlock() stub := fake.CreatePresentationStub
fakeReturns := fake.createPresentationReturns
fake.recordInvocation("CreatePresentation", []interface{}{arg1, arg2, arg3, arg4, arg5Copy})
fake.createPresentationMutex.Unlock()
if stub != nil { if stub != nil {
return stub(arg1, arg2) return stub(arg1, arg2, arg3, arg4, arg5)
} }
if specificReturn { if specificReturn {
return ret.result1, ret.result2 return ret.result1, ret.result2
...@@ -60,47 +70,47 @@ func (fake *FakeSigner) PresentationProof(arg1 context.Context, arg2 *verifiable ...@@ -60,47 +70,47 @@ func (fake *FakeSigner) PresentationProof(arg1 context.Context, arg2 *verifiable
return fakeReturns.result1, fakeReturns.result2 return fakeReturns.result1, fakeReturns.result2
} }
func (fake *FakeSigner) PresentationProofCallCount() int { func (fake *FakeSigner) CreatePresentationCallCount() int {
fake.presentationProofMutex.RLock() fake.createPresentationMutex.RLock()
defer fake.presentationProofMutex.RUnlock() defer fake.createPresentationMutex.RUnlock()
return len(fake.presentationProofArgsForCall) return len(fake.createPresentationArgsForCall)
} }
func (fake *FakeSigner) PresentationProofCalls(stub func(context.Context, *verifiable.Presentation) (*verifiable.Presentation, error)) { func (fake *FakeSigner) CreatePresentationCalls(stub func(context.Context, string, string, string, []map[string]interface{}) (map[string]interface{}, error)) {
fake.presentationProofMutex.Lock() fake.createPresentationMutex.Lock()
defer fake.presentationProofMutex.Unlock() defer fake.createPresentationMutex.Unlock()
fake.PresentationProofStub = stub fake.CreatePresentationStub = stub
} }
func (fake *FakeSigner) PresentationProofArgsForCall(i int) (context.Context, *verifiable.Presentation) { func (fake *FakeSigner) CreatePresentationArgsForCall(i int) (context.Context, string, string, string, []map[string]interface{}) {
fake.presentationProofMutex.RLock() fake.createPresentationMutex.RLock()
defer fake.presentationProofMutex.RUnlock() defer fake.createPresentationMutex.RUnlock()
argsForCall := fake.presentationProofArgsForCall[i] argsForCall := fake.createPresentationArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2 return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5
} }
func (fake *FakeSigner) PresentationProofReturns(result1 *verifiable.Presentation, result2 error) { func (fake *FakeSigner) CreatePresentationReturns(result1 map[string]interface{}, result2 error) {
fake.presentationProofMutex.Lock() fake.createPresentationMutex.Lock()
defer fake.presentationProofMutex.Unlock() defer fake.createPresentationMutex.Unlock()
fake.PresentationProofStub = nil fake.CreatePresentationStub = nil
fake.presentationProofReturns = struct { fake.createPresentationReturns = struct {
result1 *verifiable.Presentation result1 map[string]interface{}
result2 error result2 error
}{result1, result2} }{result1, result2}
} }
func (fake *FakeSigner) PresentationProofReturnsOnCall(i int, result1 *verifiable.Presentation, result2 error) { func (fake *FakeSigner) CreatePresentationReturnsOnCall(i int, result1 map[string]interface{}, result2 error) {
fake.presentationProofMutex.Lock() fake.createPresentationMutex.Lock()
defer fake.presentationProofMutex.Unlock() defer fake.createPresentationMutex.Unlock()
fake.PresentationProofStub = nil fake.CreatePresentationStub = nil
if fake.presentationProofReturnsOnCall == nil { if fake.createPresentationReturnsOnCall == nil {
fake.presentationProofReturnsOnCall = make(map[int]struct { fake.createPresentationReturnsOnCall = make(map[int]struct {
result1 *verifiable.Presentation result1 map[string]interface{}
result2 error result2 error
}) })
} }
fake.presentationProofReturnsOnCall[i] = struct { fake.createPresentationReturnsOnCall[i] = struct {
result1 *verifiable.Presentation result1 map[string]interface{}
result2 error result2 error
}{result1, result2} }{result1, result2}
} }
...@@ -175,8 +185,8 @@ func (fake *FakeSigner) VerifyPresentationReturnsOnCall(i int, result1 error) { ...@@ -175,8 +185,8 @@ func (fake *FakeSigner) VerifyPresentationReturnsOnCall(i int, result1 error) {
func (fake *FakeSigner) Invocations() map[string][][]interface{} { func (fake *FakeSigner) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock() fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock() defer fake.invocationsMutex.RUnlock()
fake.presentationProofMutex.RLock() fake.createPresentationMutex.RLock()
defer fake.presentationProofMutex.RUnlock() defer fake.createPresentationMutex.RUnlock()
fake.verifyPresentationMutex.RLock() fake.verifyPresentationMutex.RLock()
defer fake.verifyPresentationMutex.RUnlock() defer fake.verifyPresentationMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{} copiedInvocations := map[string][][]interface{}{}
......
...@@ -35,13 +35,11 @@ type Cache interface { ...@@ -35,13 +35,11 @@ type Cache interface {
} }
type Credentials 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) ParsePresentation(vpBytes []byte) (*verifiable.Presentation, error)
} }
type Signer interface { 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 VerifyPresentation(ctx context.Context, vp []byte) error
} }
...@@ -150,35 +148,26 @@ func (s *Service) Export(ctx context.Context, req *infohub.ExportRequest) (inter ...@@ -150,35 +148,26 @@ func (s *Service) Export(ctx context.Context, req *infohub.ExportRequest) (inter
return nil, err return nil, err
} }
// wrap each policy result in a verifiable credential var results []map[string]interface{}
var creds []*verifiable.Credential
for policy, result := range policyResults { for policy, result := range policyResults {
var res map[string]interface{} var res map[string]interface{}
if err := json.Unmarshal(result, &res); err != nil { 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) return nil, errors.New("error creating export", err)
} }
results = append(results, res)
// 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)
} }
// wrap all credentials in a verifiable presentation // create verifiable presentation
vp, err := s.credentials.NewPresentation(exportCfg.Contexts, creds...) vp, err := s.signer.CreatePresentation(
if err != nil { ctx,
logger.Error("failed to create verifiable presentation", zap.Error(err)) exportCfg.Issuer,
return nil, errors.New("error creating export", err) exportCfg.KeyNamespace,
} exportCfg.Key,
results,
// get presentation proof from the signer )
vp, err = s.signer.PresentationProof(ctx, vp)
if err != nil { 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) return nil, errors.New("error creating export", err)
} }
...@@ -190,6 +179,8 @@ func (s *Service) Export(ctx context.Context, req *infohub.ExportRequest) (inter ...@@ -190,6 +179,8 @@ func (s *Service) Export(ctx context.Context, req *infohub.ExportRequest) (inter
// is returned. // is returned.
// If all results are found, they are returned as map, where the key is policyName // 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. // 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) { func (s *Service) getExportData(ctx context.Context, exportName string, policyNames []string) (map[string][]byte, error) {
results := make(map[string][]byte) results := make(map[string][]byte)
for _, policy := range policyNames { for _, policy := range policyNames {
......
...@@ -4,7 +4,6 @@ import ( ...@@ -4,7 +4,6 @@ import (
"context" "context"
"testing" "testing"
"github.com/hyperledger/aries-framework-go/pkg/doc/verifiable"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/zap" "go.uber.org/zap"
...@@ -173,7 +172,7 @@ func TestService_Export(t *testing.T) { ...@@ -173,7 +172,7 @@ func TestService_Export(t *testing.T) {
errtext: "error creating export: invalid character", errtext: "error creating export: invalid character",
}, },
{ {
name: "error creating verifiable credential for data", name: "error creating verifiable presentation",
req: &goasigner.ExportRequest{ExportName: "testexport"}, req: &goasigner.ExportRequest{ExportName: "testexport"},
storage: &infohubfakes.FakeStorage{ storage: &infohubfakes.FakeStorage{
ExportConfigurationStub: func(ctx context.Context, s string) (*storage.ExportConfiguration, error) { ExportConfigurationStub: func(ctx context.Context, s string) (*storage.ExportConfiguration, error) {
...@@ -189,77 +188,16 @@ func TestService_Export(t *testing.T) { ...@@ -189,77 +188,16 @@ func TestService_Export(t *testing.T) {
return []byte(`{"allow":true}`), nil 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{ signer: &infohubfakes.FakeSigner{
PresentationProofStub: func(ctx context.Context, presentation *verifiable.Presentation) (*verifiable.Presentation, error) { CreatePresentationStub: func(ctx context.Context, issuer string, namespace string, key string, data []map[string]interface{}) (map[string]interface{}, error) {
return nil, errors.New(errors.ServiceUnavailable, "service unavailable") return nil, errors.New("some error")
}, },
}, },
errkind: errors.ServiceUnavailable, errkind: errors.Unknown,
errtext: "service unavailable", errtext: "some error",
}, },
{ {
name: "exported data is returned successfully", name: "successfully create verifiable presentation",
req: &goasigner.ExportRequest{ExportName: "testexport"}, req: &goasigner.ExportRequest{ExportName: "testexport"},
storage: &infohubfakes.FakeStorage{ storage: &infohubfakes.FakeStorage{
ExportConfigurationStub: func(ctx context.Context, s string) (*storage.ExportConfiguration, error) { ExportConfigurationStub: func(ctx context.Context, s string) (*storage.ExportConfiguration, error) {
...@@ -275,20 +213,12 @@ func TestService_Export(t *testing.T) { ...@@ -275,20 +213,12 @@ func TestService_Export(t *testing.T) {
return []byte(`{"allow":true}`), nil 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{ signer: &infohubfakes.FakeSigner{
PresentationProofStub: func(ctx context.Context, presentation *verifiable.Presentation) (*verifiable.Presentation, error) { CreatePresentationStub: func(ctx context.Context, issuer string, namespace string, key string, data []map[string]interface{}) (map[string]interface{}, error) {
return &verifiable.Presentation{ID: "did:ocm"}, nil 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"},
}, },
} }
......
...@@ -12,10 +12,13 @@ import ( ...@@ -12,10 +12,13 @@ import (
) )
type ExportConfiguration struct { type ExportConfiguration struct {
ExportName string ExportName string
Contexts []string Contexts []string
Policies map[string]interface{} Policies map[string]interface{}
CacheTTL *int CacheTTL *int
Issuer string // issuer DID
KeyNamespace string // signing key namespace
Key string // signing key name
} }
type Storage struct { type Storage struct {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment