/
convert.go
129 lines (112 loc) · 3.72 KB
/
convert.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
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package policies
import (
"fmt"
cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/pkg/errors"
)
// remap explores the policy tree depth first and remaps the "signed by"
// entries according to the remapping rules; a "signed by" rule requires
// a signature from a principal given its position in the array of principals;
// the idRemap map tells us how to remap these integers given that merging two
// policies implies deduplicating their principals
func remap(sp *cb.SignaturePolicy, idRemap map[int]int) *cb.SignaturePolicy {
switch t := sp.Type.(type) {
case *cb.SignaturePolicy_NOutOf_:
rules := []*cb.SignaturePolicy{}
for _, rule := range t.NOutOf.Rules {
// here we call remap again - we're doing a
// depth-first traversal of this policy tree
rules = append(rules, remap(rule, idRemap))
}
return &cb.SignaturePolicy{
Type: &cb.SignaturePolicy_NOutOf_{
NOutOf: &cb.SignaturePolicy_NOutOf{
N: t.NOutOf.N,
Rules: rules,
},
},
}
case *cb.SignaturePolicy_SignedBy:
// here we do the actual remapping because we have
// the "signed by" rule, whose reference to the
// principal we need to remap
newID, in := idRemap[int(t.SignedBy)]
if !in {
panic("programming error")
}
return &cb.SignaturePolicy{
Type: &cb.SignaturePolicy_SignedBy{
SignedBy: int32(newID),
},
}
default:
panic(fmt.Sprintf("invalid policy type %T", t))
}
}
// merge integrates the policy `that` into the
// policy `this`. The first argument is changed
// whereas the second isn't
func merge(this *cb.SignaturePolicyEnvelope, that *cb.SignaturePolicyEnvelope) {
// at first we build a map of principals in `this`
IDs := this.Identities
idMap := map[string]int{}
for i, id := range this.Identities {
str := id.PrincipalClassification.String() + string(id.Principal)
idMap[str] = i
}
// then we traverse each of the principals in `that`,
// deduplicate them against the ones in `this` and
// create remapping rules so that if `that` references
// a duplicate policy in this, the merged policy will
// ensure that the references in `that` point to the
// correct principal
idRemap := map[int]int{}
for i, id := range that.Identities {
str := id.PrincipalClassification.String() + string(id.Principal)
if j, in := idMap[str]; in {
idRemap[i] = j
} else {
idRemap[i] = len(IDs)
idMap[str] = len(IDs)
IDs = append(IDs, id)
}
}
this.Identities = IDs
newEntry := remap(that.Rule, idRemap)
existingRules := this.Rule.Type.(*cb.SignaturePolicy_NOutOf_).NOutOf.Rules
this.Rule.Type.(*cb.SignaturePolicy_NOutOf_).NOutOf.Rules = append(existingRules, newEntry)
}
// Convert implements the policies.Converter function to
// convert an implicit meta policy into a signature policy envelope.
func (p *ImplicitMetaPolicy) Convert() (*cb.SignaturePolicyEnvelope, error) {
converted := &cb.SignaturePolicyEnvelope{
Version: 0,
Rule: &cb.SignaturePolicy{
Type: &cb.SignaturePolicy_NOutOf_{
NOutOf: &cb.SignaturePolicy_NOutOf{
N: int32(p.Threshold),
},
},
},
}
// the conversion approach for an implicit meta
// policy is to convert each of the subpolicies,
// merge it with the previous one and return the
// merged policy
for i, subPolicy := range p.SubPolicies {
convertibleSubpolicy, ok := subPolicy.(Converter)
if !ok {
return nil, errors.Errorf("subpolicy number %d type %T of policy %s is not convertible", i, subPolicy, p.SubPolicyName)
}
spe, err := convertibleSubpolicy.Convert()
if err != nil {
return nil, errors.WithMessagef(err, "failed to convert subpolicy number %d of policy %s", i, p.SubPolicyName)
}
merge(converted, spe)
}
return converted, nil
}