Skip to content
Snippets Groups Projects
Commit ba446296 authored by Yordan Kinkov's avatar Yordan Kinkov
Browse files

Merge branch '18-rego-did-resolve-function' into 'main'

Rego extension function for DID resolving

Closes #18

See merge request !14
parents 9905a026 6e6cde1b
Branches
Tags 0.0.1
1 merge request!14Rego extension function for DID resolving
Pipeline #50713 passed
......@@ -74,8 +74,10 @@ func main() {
// register rego extension functions
{
cacheFuncs := regofunc.NewCacheFuncs(cfg.Cache.Addr, httpClient())
didResolverFuncs := regofunc.NewDIDResolverFuncs(cfg.DIDResolver.Addr, httpClient())
regofunc.Register("cacheGet", rego.Function3(cacheFuncs.CacheGetFunc()))
regofunc.Register("cacheSet", rego.Function4(cacheFuncs.CacheSetFunc()))
regofunc.Register("didResolve", rego.Function1(didResolverFuncs.Resolve()))
regofunc.Register("strictBuiltinErrors", rego.StrictBuiltinErrors(true))
}
......
......@@ -3,9 +3,10 @@ package config
import "time"
type Config struct {
HTTP httpConfig
Mongo mongoConfig
Cache cacheConfig
HTTP httpConfig
Mongo mongoConfig
Cache cacheConfig
DIDResolver didResolverConfig
LogLevel string `envconfig:"LOG_LEVEL" default:"INFO"`
}
......@@ -22,6 +23,10 @@ type cacheConfig struct {
Addr string `envconfig:"CACHE_ADDR" required:"true"`
}
type didResolverConfig struct {
Addr string `envconfig:"DID_RESOLVER_ADDR" required:"true"`
}
type mongoConfig struct {
Addr string `envconfig:"MONGO_ADDR" required:"true"`
User string `envconfig:"MONGO_USER" required:"true"`
......
package regofunc
import (
"fmt"
"net/http"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/types"
"code.vereign.com/gaiax/tsa/golib/errors"
)
type DIDResolverFuncs struct {
resolverAddr string
httpClient *http.Client
}
func NewDIDResolverFuncs(resolverAddr string, httpClient *http.Client) *DIDResolverFuncs {
return &DIDResolverFuncs{
resolverAddr: resolverAddr,
httpClient: httpClient,
}
}
func (dr *DIDResolverFuncs) Resolve() (*rego.Function, rego.Builtin1) {
return &rego.Function{
Name: "did.resolve",
Decl: types.NewFunction(types.Args(types.S), types.A),
Memoize: true,
},
func(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
var DID string
if err := ast.As(a.Value, &DID); err != nil {
return nil, fmt.Errorf("invalid DID: %s", err)
}
if DID == "" {
return nil, errors.New("DID cannot be empty")
}
req, err := http.NewRequest("GET", dr.resolverAddr+"/1.0/identifiers/"+DID, nil)
if err != nil {
return nil, err
}
resp, err := dr.httpClient.Do(req.WithContext(bctx.Context))
if err != nil {
return nil, err
}
defer resp.Body.Close() // nolint:errcheck
v, err := ast.ValueFromReader(resp.Body)
if err != nil {
return nil, err
}
return ast.NewTerm(v), nil
}
}
package regofunc_test
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/open-policy-agent/opa/rego"
"github.com/stretchr/testify/assert"
"code.vereign.com/gaiax/tsa/policy/internal/regofunc"
)
func TestResolveFunc(t *testing.T) {
expected := `{"data":{"@context":"https://w3id.org/did-resolution/v1","didDocument":"document"}}`
resolverSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprint(w, expected)
}))
defer resolverSrv.Close()
DIDResolverFuncs := regofunc.NewDIDResolverFuncs(resolverSrv.URL, http.DefaultClient)
r := rego.New(
rego.Query(`did.resolve("did:indy:idunion:BDrEcHc8Tb4Lb2VyQZWEDE")`),
rego.Function1(DIDResolverFuncs.Resolve()),
)
resultSet, err := r.Eval(context.Background())
assert.NoError(t, err)
resultBytes, err := json.Marshal(resultSet[0].Expressions[0].Value)
assert.NoError(t, err)
assert.Equal(t, expected, string(resultBytes))
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment