diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a3664cd114635e6f58114c64dfb7aabcbb45c7f8..e7cfd8f5d6dc3f9b267c6511fdbffa66ff0fdb37 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,7 +6,7 @@ before_script: - cd /go/src/gitlab.com/${CI_PROJECT_PATH} unit tests: - image: golang:1.19.4 + image: golang:1.20.2 stage: test tags: - amd64-docker @@ -28,7 +28,7 @@ lint: - golangci-lint run govulncheck: - image: golang:1.19.4 + image: golang:1.20.2 stage: test tags: - amd64-docker diff --git a/ocm/client.go b/ocm/client.go index e6c448e8b9d7406531f5640e156b20b24a2c90a0..4d1b2fa5ba4f04a1cc49a8e6a443960ba927688a 100644 --- a/ocm/client.go +++ b/ocm/client.go @@ -1,6 +1,7 @@ package ocm import ( + "bytes" "context" "encoding/json" "fmt" @@ -11,8 +12,9 @@ import ( ) const ( - proofOutOfBandPath = "/v1/out-of-band-proof" - proofPresentationPath = "/v1/find-by-presentation-id" + proofOutOfBandPath = "/v1/out-of-band-proof" + proofOutOfBandRequestPath = "/v1/send-out-of-band-presentation-request" + proofPresentationPath = "/v1/find-by-presentation-id" ) // Client is the OCM service client @@ -70,16 +72,19 @@ func (c *Client) GetLoginProofInvitation(ctx context.Context, credTypes []string return &response, nil } -// GetLoginProofResult calls the "find-by-presentation-id" endpoint in the OCM. -func (c *Client) GetLoginProofResult(ctx context.Context, presentationID string) (*LoginProofResultResponse, error) { - req, err := http.NewRequestWithContext(ctx, "GET", c.proofManagerAddr+proofPresentationPath, nil) +// SendOutOfBandRequest calls the "send out of band presentation request" endpoint on +// the "out-of-band" protocol in the OCM. +func (c *Client) SendOutOfBandRequest(ctx context.Context, r map[string]interface{}) (*LoginProofInvitationResponse, error) { + body, err := json.Marshal(r) if err != nil { return nil, err } - v := url.Values{} - v.Add("presentationId", presentationID) - req.URL.RawQuery = v.Encode() + req, err := http.NewRequestWithContext(ctx, "POST", c.proofManagerAddr+proofOutOfBandRequestPath, bytes.NewBuffer(body)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") resp, err := c.httpClient.Do(req) if err != nil { @@ -87,7 +92,7 @@ func (c *Client) GetLoginProofResult(ctx context.Context, presentationID string) } defer resp.Body.Close() // nolint:errcheck - if resp.StatusCode != http.StatusOK { + if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected response code: %s", resp.Status) } @@ -96,10 +101,63 @@ func (c *Client) GetLoginProofResult(ctx context.Context, presentationID string) return nil, err } - var response LoginProofResultResponse + var response LoginProofInvitationResponse if err := json.Unmarshal(bytes, &response); err != nil { return nil, err } return &response, nil } + +// GetLoginProofResult calls the "find-by-presentation-id" endpoint in the OCM. +func (c *Client) GetLoginProofResult(ctx context.Context, presentationID string) (*LoginProofResultResponse, error) { + resBytes, err := c.findByPresentationID(ctx, presentationID) + if err != nil { + return nil, err + } + + var response LoginProofResultResponse + if err := json.Unmarshal(resBytes, &response); err != nil { + return nil, err + } + + return &response, nil +} + +// GetRawLoginProofResult calls the "find-by-presentation-id" endpoint in the OCM and returns the raw result. +func (c *Client) GetRawLoginProofResult(ctx context.Context, presentationID string) (map[string]interface{}, error) { + resBytes, err := c.findByPresentationID(ctx, presentationID) + if err != nil { + return nil, err + } + + var response map[string]interface{} + if err := json.Unmarshal(resBytes, &response); err != nil { + return nil, err + } + + return response, nil +} + +func (c *Client) findByPresentationID(ctx context.Context, presentationID string) ([]byte, error) { + req, err := http.NewRequestWithContext(ctx, "GET", c.proofManagerAddr+proofPresentationPath, nil) + if err != nil { + return nil, err + } + + v := url.Values{} + v.Add("presentationId", presentationID) + req.URL.RawQuery = v.Encode() + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() // nolint:errcheck + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected response code: %s", resp.Status) + } + + return io.ReadAll(resp.Body) +} diff --git a/ocm/client_test.go b/ocm/client_test.go index ec2a9967aaf326f69d823365bb03b3975f9b5678..fd12f49d3750bf9ced0d29aa3901c8362835df2f 100644 --- a/ocm/client_test.go +++ b/ocm/client_test.go @@ -46,6 +46,76 @@ func Test_GetLoginProofInvitationErr(t *testing.T) { assert.Contains(t, err.Error(), "unexpected response code") } +func Test_SendOutOfBandRequestSuccess(t *testing.T) { + expected := &ocm.LoginProofInvitationResponse{ + StatusCode: 200, + Message: "success", + Data: ocm.LoginProofInvitationResponseData{}, + } + + ocmServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(expected) + })) + + client := ocm.New(ocmServer.URL) + res, err := client.SendOutOfBandRequest(context.Background(), map[string]interface{}{ + "attributes": []map[string]string{ + { + "schemaId": "7KuDTpQh3GJ7Gp6kErpWvM:2:principalTestSchema:1.0", + "credentialDefinitionId": "7KuDTpQh3GJ7Gp6kErpWvM:3:CL:40329:principalTestCredDefExpir", + "attributeName": "prcLastName", + "value": "", + }, + { + "schemaId": "7KuDTpQh3GJ7Gp6kErpWvM:2:principalTestSchema:1.0", + "credentialDefinitionId": "7KuDTpQh3GJ7Gp6kErpWvM:3:CL:40329:principalTestCredDefExpir", + "attributeName": "email", + "value": "", + }, + }, + "options": map[string]string{ + "type": "Aries1.0", + }, + }) + + assert.NoError(t, err) + assert.Equal(t, expected.StatusCode, res.StatusCode) + assert.Equal(t, expected.Message, res.Message) + assert.Equal(t, expected.Data, res.Data) +} + +func Test_SendOutOfBandRequestErr(t *testing.T) { + ocmServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + + client := ocm.New(ocmServer.URL) + res, err := client.SendOutOfBandRequest(context.Background(), map[string]interface{}{ + "attributes": []map[string]string{ + { + "schemaId": "7KuDTpQh3GJ7Gp6kErpWvM:2:principalTestSchema:1.0", + "credentialDefinitionId": "7KuDTpQh3GJ7Gp6kErpWvM:3:CL:40329:principalTestCredDefExpir", + "attributeName": "prcLastName", + "value": "", + }, + { + "schemaId": "7KuDTpQh3GJ7Gp6kErpWvM:2:principalTestSchema:1.0", + "credentialDefinitionId": "7KuDTpQh3GJ7Gp6kErpWvM:3:CL:40329:principalTestCredDefExpir", + "attributeName": "email", + "value": "", + }, + }, + "options": map[string]string{ + "type": "Aries1.0", + }, + }) + + assert.Nil(t, res) + assert.Error(t, err) + assert.Contains(t, err.Error(), "unexpected response code") +} + func TestClient_GetLoginProofResultSuccess(t *testing.T) { expected := &ocm.LoginProofResultResponse{ StatusCode: 200, @@ -79,3 +149,51 @@ func Test_GetLoginProofResultErr(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "unexpected response code") } + +func Test_GetRawLoginProofResultSuccess(t *testing.T) { + expected := map[string]interface{}{ + "statusCode": float64(200), + "message": "Proof presentation fetch successfully", + "data": map[string]interface{}{ + "state": "done", + "presentations": []interface{}{ + map[string]interface{}{ + "schemaId": "7KuDTpQh3GJ7Gp6kErpWvM:2:principalTestSchema:1.0", + "credDefId": "7KuDTpQh3GJ7Gp6kErpWvM:3:CL:40329:principalTestCredDefExpire", + "revRegId": nil, + "timestamp": nil, + "credentialSubject": map[string]interface{}{ + "email": "23957edb-991d-4b5f-bf76-153103ba45b7", + "prcLastName": "NA", + }, + }, + }, + }, + } + + ocmServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(expected) + })) + + client := ocm.New(ocmServer.URL) + res, err := client.GetRawLoginProofResult(context.Background(), "2cf01406-b15f-4960-a6a7-7bc62cd37a3c") + + assert.NoError(t, err) + assert.Equal(t, expected["statusCode"], res["statusCode"]) + assert.Equal(t, expected["message"], res["message"]) + assert.Equal(t, expected["data"], res["data"]) +} + +func Test_GetRawLoginProofResultErr(t *testing.T) { + ocmServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + + client := ocm.New(ocmServer.URL) + res, err := client.GetRawLoginProofResult(context.Background(), "2cf01406-b15f-4960-a6a7-7bc62cd37a3c") + + assert.Nil(t, res) + assert.Error(t, err) + assert.Contains(t, err.Error(), "unexpected response code") +}