forked from vanadium-archive/go.ref
/
caveat.go
135 lines (120 loc) · 3.78 KB
/
caveat.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
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"strings"
"v.io/v23/security"
"v.io/v23/vdl"
"v.io/x/ref/lib/vdl/build"
"v.io/x/ref/lib/vdl/compile"
"v.io/x/ref/lib/vdl/parse"
)
// caveatsFlag defines a flag.Value for receiving multiple caveat definitions.
type caveatsFlag struct {
caveatInfos []caveatInfo
}
type caveatInfo struct {
expr, params string
}
// Implements flag.Value.Get
func (c caveatsFlag) Get() interface{} {
return c.caveatInfos
}
// Implements flag.Value.Set
// Set expects s to be of the form:
// caveatExpr=VDLExpressionOfParam
func (c *caveatsFlag) Set(s string) error {
exprAndParam := strings.SplitN(s, "=", 2)
if len(exprAndParam) != 2 {
return fmt.Errorf("incorrect caveat format: %s", s)
}
c.caveatInfos = append(c.caveatInfos, caveatInfo{exprAndParam[0], exprAndParam[1]})
return nil
}
// Implements flag.Value.String
func (c caveatsFlag) String() string {
return fmt.Sprint(c.caveatInfos)
}
func (c caveatsFlag) usage() string {
return `"package/path".CaveatName:VDLExpressionParam to attach to this blessing`
}
func (c caveatsFlag) Compile() ([]security.Caveat, error) {
if len(c.caveatInfos) == 0 {
return nil, nil
}
env := compile.NewEnv(-1)
if err := buildPackages(c.caveatInfos, env); err != nil {
return nil, err
}
var caveats []security.Caveat
for _, info := range c.caveatInfos {
caveat, err := newCaveat(info, env)
if err != nil {
return nil, err
}
caveats = append(caveats, caveat)
}
return caveats, nil
}
func buildPackages(caveatInfos []caveatInfo, env *compile.Env) error {
var (
pkgNames []string
exprs []string
)
for _, info := range caveatInfos {
exprs = append(exprs, info.expr, info.params)
}
for _, pexpr := range parse.ParseExprs(strings.Join(exprs, ","), env.Errors) {
pkgNames = append(pkgNames, parse.ExtractExprPackagePaths(pexpr)...)
}
if !env.Errors.IsEmpty() {
return fmt.Errorf("can't build expressions %v:\n%v", exprs, env.Errors)
}
pkgs := build.TransitivePackages(pkgNames, build.UnknownPathIsError, build.Opts{}, env.Errors)
if !env.Errors.IsEmpty() {
return fmt.Errorf("failed to get transitive packages %v: %s", pkgNames, env.Errors)
}
for _, p := range pkgs {
if build.BuildPackage(p, env); !env.Errors.IsEmpty() {
return fmt.Errorf("failed to build package(%v): %v", p, env.Errors)
}
}
return nil
}
func newCaveat(info caveatInfo, env *compile.Env) (security.Caveat, error) {
caveatDesc, err := compileCaveatDesc(info.expr, env)
if err != nil {
return security.Caveat{}, err
}
param, err := compileParams(info.params, caveatDesc.ParamType, env)
if err != nil {
return security.Caveat{}, err
}
return security.NewCaveat(caveatDesc, param)
}
func compileCaveatDesc(expr string, env *compile.Env) (security.CaveatDescriptor, error) {
vdlValues := build.BuildExprs(expr, []*vdl.Type{vdl.TypeOf(security.CaveatDescriptor{})}, env)
if err := env.Errors.ToError(); err != nil {
return security.CaveatDescriptor{}, fmt.Errorf("can't build caveat desc %s:\n%v", expr, err)
}
if len(vdlValues) == 0 {
return security.CaveatDescriptor{}, fmt.Errorf("no caveat descriptors were built")
}
var desc security.CaveatDescriptor
if err := vdl.Convert(&desc, vdlValues[0]); err != nil {
return security.CaveatDescriptor{}, err
}
return desc, nil
}
func compileParams(paramData string, vdlType *vdl.Type, env *compile.Env) (interface{}, error) {
params := build.BuildExprs(paramData, []*vdl.Type{vdlType}, env)
if !env.Errors.IsEmpty() {
return nil, fmt.Errorf("can't build param data %s:\n%v", paramData, env.Errors)
}
if len(params) == 0 {
return security.CaveatDescriptor{}, fmt.Errorf("no caveat params were built")
}
return params[0], nil
}