Skip to content

Commit

Permalink
implement parse SignaturePolicyEnvelope to human readable expression (#…
Browse files Browse the repository at this point in the history
…135)

Signed-off-by: 1gezhanghao <[email protected]>
Signed-off-by: xvkong <[email protected]>
Co-authored-by: Mark S. Lewis <[email protected]>
  • Loading branch information
1gezhanghao and bestbeforetoday authored Jul 7, 2023
1 parent 8a2f81e commit b782815
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 0 deletions.
66 changes: 66 additions & 0 deletions pkg/chaincode/signaturepolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ SPDX-License-Identifier: Apache-2.0
package chaincode

import (
"bytes"
"fmt"
"reflect"
"regexp"
Expand Down Expand Up @@ -391,3 +392,68 @@ func signaturePolicyEnvelopeFromString(policy string) (*cb.SignaturePolicyEnvelo

return p, nil
}

// SignaturePolicyEnvelopeToString parse a SignaturePolicyEnvelope to human readable expression
// the returned expression is GATE(P[, P])
//
// where:
// - GATE is either "and" or "or" or "outof"
// - P is either a principal or another nested call to GATE
//
// A principal is defined as:
//
// # ORG.ROLE
//
// where:
// - ORG is a string (representing the MSP identifier)
// - ROLE takes the value of any of the RoleXXX constants representing
// the required role
func SignaturePolicyEnvelopeToString(policy *cb.SignaturePolicyEnvelope) (string, error) {
ids := []string{}
for _, id := range policy.GetIdentities() {
var mspRole mb.MSPRole
if err := proto.Unmarshal(id.GetPrincipal(), &mspRole); err != nil {
return "", err
}

mspID := mspRole.GetMspIdentifier() + "." + strings.ToLower(mb.MSPRole_MSPRoleType_name[int32(mspRole.GetRole())])
ids = append(ids, mspID)
}

var buf bytes.Buffer
policyParse(policy.GetRule(), ids, &buf)
return buf.String(), nil
}

// recursive parse
func policyParse(rule *cb.SignaturePolicy, ids []string, buf *bytes.Buffer) {
switch p := rule.GetType().(type) {
case *cb.SignaturePolicy_SignedBy:
buf.WriteString("'")
buf.WriteString(ids[p.SignedBy])
buf.WriteString("'")

case *cb.SignaturePolicy_NOutOf_:
n := p.NOutOf.GetN()
rules := p.NOutOf.GetRules()

switch n {
case int32(len(rules)):
buf.WriteString("AND(")
case 1:
buf.WriteString("OR(")
default:
buf.WriteString("OutOf(")
buf.WriteString(strconv.Itoa(int(n)))
buf.WriteString(",")
}

for i, r := range rules {
if i > 0 {
buf.WriteString(",")
}
policyParse(r, ids, buf)
}
buf.WriteString(")")
}
}
30 changes: 30 additions & 0 deletions pkg/chaincode/signaturepolicy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package chaincode

import (
"fmt"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = DescribeTable("signaturepolicyenvelope to string",
func(expression string) {
//gen a SignaturePolicyEnvelope from expression
applicationPolicy, err := NewApplicationPolicy(expression, "")
Expect(err).NotTo(HaveOccurred())
policy := applicationPolicy.GetSignaturePolicy()

//parse the SignaturePolicyEnvelope back to expression
dstExpression, err := SignaturePolicyEnvelopeToString(policy)
Expect(err).NotTo(HaveOccurred())

fmt.Println("src Expression:", expression)
fmt.Println("dst Expression:", dstExpression)

Expect(dstExpression).To(Equal(expression))
},
Entry("When keyword has OR", `OR('Org3MSP.peer','Org1MSP.admin','Org2MSP.member')`),
Entry("When keyword has AND", `AND('Org3MSP.peer','Org1MSP.admin','Org2MSP.member')`),
Entry("When keyword has AND,OR", `AND('Org3MSP.peer',OR('Org1MSP.admin','Org2MSP.member'))`),
Entry("When keyword has OutOf", `OutOf(2,'Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')`),
)

0 comments on commit b782815

Please sign in to comment.