github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/cli/smartcontract/permission.go (about)

     1  package smartcontract
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
     8  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
     9  	"github.com/nspcc-dev/neo-go/pkg/util"
    10  	"gopkg.in/yaml.v3"
    11  )
    12  
    13  type permission manifest.Permission
    14  
    15  const (
    16  	permHashKey   = "hash"
    17  	permGroupKey  = "group"
    18  	permMethodKey = "methods"
    19  )
    20  
    21  func (p permission) MarshalYAML() (any, error) {
    22  	m := yaml.Node{Kind: yaml.MappingNode}
    23  	switch p.Contract.Type {
    24  	case manifest.PermissionWildcard:
    25  	case manifest.PermissionHash:
    26  		m.Content = append(m.Content,
    27  			&yaml.Node{Kind: yaml.ScalarNode, Value: permHashKey},
    28  			&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(util.Uint160).StringLE()})
    29  	case manifest.PermissionGroup:
    30  		m.Content = append(m.Content,
    31  			&yaml.Node{Kind: yaml.ScalarNode, Value: permGroupKey},
    32  			&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(*keys.PublicKey).StringCompressed()})
    33  	default:
    34  		return nil, fmt.Errorf("invalid permission type: %d", p.Contract.Type)
    35  	}
    36  
    37  	var val any = "*"
    38  	if !p.Methods.IsWildcard() {
    39  		val = p.Methods.Value
    40  	}
    41  
    42  	n := &yaml.Node{Kind: yaml.ScalarNode}
    43  	err := n.Encode(val)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	m.Content = append(m.Content,
    48  		&yaml.Node{Kind: yaml.ScalarNode, Value: permMethodKey},
    49  		n)
    50  
    51  	return m, nil
    52  }
    53  
    54  func (p *permission) UnmarshalYAML(unmarshal func(any) error) error {
    55  	var m map[string]any
    56  	if err := unmarshal(&m); err != nil {
    57  		return err
    58  	}
    59  
    60  	if err := p.fillType(m); err != nil {
    61  		return err
    62  	}
    63  
    64  	return p.fillMethods(m)
    65  }
    66  
    67  func (p *permission) fillType(m map[string]any) error {
    68  	vh, ok1 := m[permHashKey]
    69  	vg, ok2 := m[permGroupKey]
    70  	switch {
    71  	case ok1 && ok2:
    72  		return errors.New("permission must have either 'hash' or 'group' field")
    73  	case ok1:
    74  		s, ok := vh.(string)
    75  		if !ok {
    76  			return errors.New("invalid 'hash' type")
    77  		}
    78  
    79  		u, err := util.Uint160DecodeStringLE(s)
    80  		if err != nil {
    81  			return err
    82  		}
    83  
    84  		p.Contract.Type = manifest.PermissionHash
    85  		p.Contract.Value = u
    86  	case ok2:
    87  		s, ok := vg.(string)
    88  		if !ok {
    89  			return errors.New("invalid 'hash' type")
    90  		}
    91  
    92  		pub, err := keys.NewPublicKeyFromString(s)
    93  		if err != nil {
    94  			return err
    95  		}
    96  
    97  		p.Contract.Type = manifest.PermissionGroup
    98  		p.Contract.Value = pub
    99  	default:
   100  		p.Contract.Type = manifest.PermissionWildcard
   101  	}
   102  	return nil
   103  }
   104  
   105  func (p *permission) fillMethods(m map[string]any) error {
   106  	methods, ok := m[permMethodKey]
   107  	if !ok {
   108  		return errors.New("'methods' field is missing from permission")
   109  	}
   110  
   111  	switch mt := methods.(type) {
   112  	case string:
   113  		if mt == "*" {
   114  			p.Methods.Value = nil
   115  			return nil
   116  		}
   117  	case []any:
   118  		ms := make([]string, len(mt))
   119  		for i := range mt {
   120  			ms[i], ok = mt[i].(string)
   121  			if !ok {
   122  				return errors.New("invalid permission method name")
   123  			}
   124  		}
   125  		p.Methods.Value = ms
   126  		return nil
   127  	default:
   128  	}
   129  	return errors.New("'methods' field is invalid")
   130  }