diff --git a/internal/regofunc/signer.go b/internal/regofunc/signer.go index 8eedb65851fb2377c9fd6ca698860ddb71e4761b..734585723aeb17ffaf8015ccef2a2b342fa87ad0 100644 --- a/internal/regofunc/signer.go +++ b/internal/regofunc/signer.go @@ -191,7 +191,7 @@ func (sf *SignerFuncs) CreateProof() (*rego.Function, rego.Builtin1) { defer resp.Body.Close() // nolint:errcheck if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("unexpected response from signer: %d", resp.StatusCode) + return nil, fmt.Errorf("unexpected response from signer: %s", resp.Status) } v, err := ast.ValueFromReader(resp.Body) @@ -256,7 +256,7 @@ func (sf *SignerFuncs) VerifyProof() (*rego.Function, rego.Builtin1) { defer resp.Body.Close() // nolint:errcheck if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("unexpected response from signer: %d", resp.StatusCode) + return nil, fmt.Errorf("unexpected response from signer: %s", resp.Status) } var result struct { diff --git a/internal/regofunc/signer_test.go b/internal/regofunc/signer_test.go index 77fad987b0b6e8b0bf78f910a8ff48d7374c9d9a..1adb9fb66abfc1152fe89faa3031a412fb0dbb9e 100644 --- a/internal/regofunc/signer_test.go +++ b/internal/regofunc/signer_test.go @@ -96,3 +96,154 @@ func TestIssuerDID(t *testing.T) { assert.NoError(t, err) assert.Equal(t, expected, string(resultBytes)) } + +func TestCreateProof(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + signerResponseCode int + errtext string + }{ + { + name: "missing credential type", + input: map[string]interface{}{"vc": "data"}, + errtext: "credential data does not specify type", + }, + { + name: "unknown credential type", + input: map[string]interface{}{"type": "non-existing-type"}, + errtext: "unknown credential type", + }, + { + name: "signer returns error for VC", + input: map[string]interface{}{"type": "VerifiableCredential"}, + signerResponseCode: http.StatusBadRequest, + errtext: "400 Bad Request", + }, + { + name: "signer returns error for VP", + input: map[string]interface{}{"type": "VerifiablePresentation"}, + signerResponseCode: http.StatusBadRequest, + errtext: "400 Bad Request", + }, + { + name: "signer returns successfully", + input: map[string]interface{}{"type": "VerifiableCredential"}, + signerResponseCode: http.StatusOK, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + expected := `{"vc":"data"}` + signerSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(test.signerResponseCode) + _, _ = fmt.Fprint(w, expected) + })) + defer signerSrv.Close() + + keysFuncs := regofunc.NewSignerFuncs(signerSrv.URL, http.DefaultClient) + query, err := rego.New( + rego.Query(`proof.create(input)`), + rego.Function1(keysFuncs.CreateProof()), + rego.StrictBuiltinErrors(true), + ).PrepareForEval(context.Background()) + assert.NoError(t, err) + + resultSet, err := query.Eval(context.Background(), rego.EvalInput(test.input)) + if err != nil { + assert.Contains(t, err.Error(), test.errtext) + } else { + assert.NotEmpty(t, resultSet) + assert.NotEmpty(t, resultSet[0].Expressions) + resultBytes, err := json.Marshal(resultSet[0].Expressions[0].Value) + assert.NoError(t, err) + assert.Equal(t, expected, string(resultBytes)) + } + }) + } +} + +func TestVerifyProof(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + signerResponseCode int + errtext string + }{ + { + name: "invalid credential", + input: nil, + errtext: "credential data does not specify type", + }, + { + name: "missing credential type", + input: map[string]interface{}{"vc": "data"}, + errtext: "credential data does not specify type", + }, + { + name: "credential type is not string", + input: map[string]interface{}{"type": 123}, + signerResponseCode: http.StatusBadRequest, + errtext: "invalid credential type, string is expected", + }, + { + name: "missing proof section", + input: map[string]interface{}{"type": "VerifiableCredential"}, + errtext: "credential data does contain proof section", + }, + { + name: "unknown credential type", + input: map[string]interface{}{"proof": "iamhere", "type": "non-existing-type"}, + errtext: "unknown credential type", + }, + { + name: "signer returns error for VC", + input: map[string]interface{}{"proof": "iamhere", "type": "VerifiableCredential"}, + signerResponseCode: http.StatusBadRequest, + errtext: "400 Bad Request", + }, + { + name: "signer returns error for VP", + input: map[string]interface{}{"proof": "iamhere", "type": "VerifiablePresentation"}, + signerResponseCode: http.StatusBadRequest, + errtext: "400 Bad Request", + }, + { + name: "signer returns successfully", + input: map[string]interface{}{"proof": "iamhere", "type": "VerifiableCredential"}, + signerResponseCode: http.StatusOK, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + expected := `{"valid":true}` + signerSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(test.signerResponseCode) + _, _ = fmt.Fprint(w, expected) + })) + defer signerSrv.Close() + + keysFuncs := regofunc.NewSignerFuncs(signerSrv.URL, http.DefaultClient) + query, err := rego.New( + rego.Query(`proof.verify(input)`), + rego.Function1(keysFuncs.VerifyProof()), + rego.StrictBuiltinErrors(true), + ).PrepareForEval(context.Background()) + assert.NoError(t, err) + + resultSet, err := query.Eval(context.Background(), rego.EvalInput(test.input)) + if err != nil { + assert.NotEmpty(t, test.errtext, "test case must contain error, but doesn't") + assert.Contains(t, err.Error(), test.errtext) + } else { + assert.NotEmpty(t, resultSet) + assert.NotEmpty(t, resultSet[0].Expressions) + valid, ok := resultSet[0].Expressions[0].Value.(bool) + assert.True(t, ok) + assert.True(t, valid) + } + }) + } +}