-
Notifications
You must be signed in to change notification settings - Fork 23
/
object.go
146 lines (124 loc) · 3.62 KB
/
object.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package ds
import (
"bytes"
dsc3 "github.com/aserto-dev/go-directory/aserto/directory/common/v3"
dsr3 "github.com/aserto-dev/go-directory/aserto/directory/reader/v3"
"github.com/aserto-dev/go-directory/pkg/convert"
"github.com/aserto-dev/topaz/resolvers"
"google.golang.org/protobuf/encoding/protojson"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/types"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
)
// RegisterObject - ds.object
//
// v3 (latest) request format:
//
// ds.object({
// "object_type": "",
// "object_id": "",
// "with_relation": false
// })
//
// v2 request format:
//
// ds.object({
// "type": "",
// "key": ""
// })
func RegisterObject(logger *zerolog.Logger, fnName string, dr resolvers.DirectoryResolver) (*rego.Function, rego.Builtin1) {
return ®o.Function{
Name: fnName,
Decl: types.NewFunction(types.Args(types.A), types.A),
Memoize: true,
},
func(bctx rego.BuiltinContext, op1 *ast.Term) (*ast.Term, error) {
var (
args struct {
ObjectType string `json:"object_type,omitempty"` // v3 object_type
ObjectID string `json:"object_id,omitempty"` // v3 object_id
WithRelations bool `json:"with_relations"` // v3 with_relations (false in case of v2)
Type string `json:"type,omitempty"` // v2 type
Key string `json:"key,omitempty"` // v2 key
}
outputV2 bool
req *dsr3.GetObjectRequest
)
if err := ast.As(op1.Value, &args); err != nil {
return nil, errors.Wrapf(err, "failed to parse ds.object input message")
}
req = &dsr3.GetObjectRequest{
ObjectType: args.ObjectType,
ObjectId: args.ObjectID,
WithRelations: args.WithRelations,
}
if args.ObjectType == "" && args.ObjectID == "" && args.Type != "" && args.Key != "" {
req = &dsr3.GetObjectRequest{
ObjectType: args.Type,
ObjectId: args.Key,
WithRelations: false,
}
outputV2 = true
}
if proto.Equal(req, &dsr3.GetObjectRequest{}) {
return helpMsg(fnName, &dsr3.GetObjectRequest{
ObjectType: "",
ObjectId: "",
WithRelations: false,
})
}
client, err := dr.GetDS(bctx.Context)
if err != nil {
return nil, errors.Wrapf(err, "get directory client")
}
resp, err := client.GetObject(bctx.Context, req)
switch {
case status.Code(err) == codes.NotFound:
traceError(&bctx, fnName, err)
astVal, err := ast.InterfaceToValue(map[string]any{})
if err != nil {
return nil, err
}
return ast.NewTerm(astVal), nil
case err != nil:
return nil, err
}
if outputV2 {
v, err := v2Value(resp.Result)
if err != nil {
return nil, err
}
return ast.NewTerm(v), nil
}
buf := new(bytes.Buffer)
if err := ProtoToBuf(buf, resp); err != nil {
return nil, err
}
pbs := structpb.Struct{}
if err := protojson.Unmarshal(buf.Bytes(), &pbs); err != nil {
return nil, err
}
result := pbs.Fields["result"].AsInterface().(map[string]interface{})
relations := pbs.Fields["relations"].AsInterface()
result["relations"] = relations
v, err := ast.InterfaceToValue(result)
if err != nil {
return nil, err
}
return ast.NewTerm(v), nil
}
}
func v2Value(obj *dsc3.Object) (ast.Value, error) {
buf := new(bytes.Buffer)
v2 := convert.ObjectToV2(obj)
if err := ProtoToBuf(buf, v2); err != nil {
return nil, err
}
return ast.ValueFromReader(buf)
}