github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/smartcontract/manifest/permission_test.go (about)

     1  package manifest
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/nspcc-dev/neo-go/internal/random"
    10  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    11  	"github.com/nspcc-dev/neo-go/pkg/util"
    12  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestNewPermission(t *testing.T) {
    17  	require.Panics(t, func() { NewPermission(PermissionWildcard, util.Uint160{}) })
    18  	require.Panics(t, func() { NewPermission(PermissionHash) })
    19  	require.Panics(t, func() { NewPermission(PermissionHash, 1) })
    20  	require.Panics(t, func() { NewPermission(PermissionGroup) })
    21  	require.Panics(t, func() { NewPermission(PermissionGroup, util.Uint160{}) })
    22  }
    23  
    24  func TestPermissionIsValid(t *testing.T) {
    25  	p := Permission{}
    26  	require.NoError(t, p.IsValid())
    27  
    28  	p.Methods.Add("")
    29  	require.Error(t, p.IsValid())
    30  
    31  	p.Methods.Value = nil
    32  	p.Methods.Add("qwerty")
    33  	require.NoError(t, p.IsValid())
    34  
    35  	p.Methods.Add("poiuyt")
    36  	require.NoError(t, p.IsValid())
    37  
    38  	p.Methods.Add("qwerty")
    39  	require.Error(t, p.IsValid())
    40  }
    41  
    42  func TestPermissionsAreValid(t *testing.T) {
    43  	p := Permissions{}
    44  	require.NoError(t, p.AreValid())
    45  
    46  	p = append(p, Permission{Methods: WildStrings{Value: []string{""}}})
    47  	require.Error(t, p.AreValid())
    48  
    49  	p = p[:0]
    50  	p = append(p, *NewPermission(PermissionHash, util.Uint160{1, 2, 3}))
    51  	require.NoError(t, p.AreValid())
    52  
    53  	priv0, err := keys.NewPrivateKey()
    54  	require.NoError(t, err)
    55  	priv1, err := keys.NewPrivateKey()
    56  	require.NoError(t, err)
    57  
    58  	p = append(p, *NewPermission(PermissionGroup, priv0.PublicKey()))
    59  	require.NoError(t, p.AreValid())
    60  
    61  	p = append(p, *NewPermission(PermissionGroup, priv1.PublicKey()))
    62  	require.NoError(t, p.AreValid())
    63  
    64  	p = append(p, *NewPermission(PermissionWildcard))
    65  	require.NoError(t, p.AreValid())
    66  
    67  	p = append(p, *NewPermission(PermissionHash, util.Uint160{3, 2, 1}))
    68  	require.NoError(t, p.AreValid())
    69  
    70  	p = append(p, *NewPermission(PermissionWildcard))
    71  	require.Error(t, p.AreValid())
    72  
    73  	p = append(p[:len(p)-1], *NewPermission(PermissionHash, util.Uint160{1, 2, 3}))
    74  	require.Error(t, p.AreValid())
    75  
    76  	p = append(p[:len(p)-1], *NewPermission(PermissionGroup, priv0.PublicKey()))
    77  	require.Error(t, p.AreValid())
    78  }
    79  
    80  func TestPermission_MarshalJSON(t *testing.T) {
    81  	t.Run("wildcard", func(t *testing.T) {
    82  		expected := NewPermission(PermissionWildcard)
    83  		expected.Methods.Restrict()
    84  		testMarshalUnmarshal(t, expected, NewPermission(PermissionWildcard))
    85  	})
    86  
    87  	t.Run("group", func(t *testing.T) {
    88  		expected := NewPermission(PermissionWildcard)
    89  		expected.Contract.Type = PermissionGroup
    90  		priv, err := keys.NewPrivateKey()
    91  		require.NoError(t, err)
    92  		expected.Contract.Value = priv.PublicKey()
    93  		expected.Methods.Add("method1")
    94  		expected.Methods.Add("method2")
    95  		testMarshalUnmarshal(t, expected, NewPermission(PermissionWildcard))
    96  	})
    97  
    98  	t.Run("hash", func(t *testing.T) {
    99  		expected := NewPermission(PermissionWildcard)
   100  		expected.Contract.Type = PermissionHash
   101  		expected.Contract.Value = random.Uint160()
   102  		testMarshalUnmarshal(t, expected, NewPermission(PermissionWildcard))
   103  	})
   104  }
   105  
   106  func TestPermissionDesc_MarshalJSON(t *testing.T) {
   107  	t.Run("uint160 with 0x", func(t *testing.T) {
   108  		u := random.Uint160()
   109  		s := u.StringLE()
   110  		js := []byte(fmt.Sprintf(`"0x%s"`, s))
   111  		d := new(PermissionDesc)
   112  		require.NoError(t, json.Unmarshal(js, d))
   113  		require.Equal(t, u, d.Value.(util.Uint160))
   114  	})
   115  
   116  	t.Run("invalid uint160", func(t *testing.T) {
   117  		d := new(PermissionDesc)
   118  		s := random.String(util.Uint160Size * 2)
   119  		js := []byte(fmt.Sprintf(`"ok%s"`, s))
   120  		require.Error(t, json.Unmarshal(js, d))
   121  
   122  		js = []byte(fmt.Sprintf(`"%s"`, s))
   123  		require.Error(t, json.Unmarshal(js, d))
   124  	})
   125  
   126  	t.Run("invalid public key", func(t *testing.T) {
   127  		d := new(PermissionDesc)
   128  		s := random.String(65)
   129  		s = "k" + s // not a hex
   130  		js := []byte(fmt.Sprintf(`"%s"`, s))
   131  		require.Error(t, json.Unmarshal(js, d))
   132  	})
   133  
   134  	t.Run("not a string", func(t *testing.T) {
   135  		d := new(PermissionDesc)
   136  		js := []byte(`123`)
   137  		require.Error(t, json.Unmarshal(js, d))
   138  	})
   139  
   140  	t.Run("invalid string", func(t *testing.T) {
   141  		d := new(PermissionDesc)
   142  		js := []byte(`"invalid length"`)
   143  		require.Error(t, json.Unmarshal(js, d))
   144  	})
   145  }
   146  
   147  func testMarshalUnmarshal(t *testing.T, expected, actual any) {
   148  	data, err := json.Marshal(expected)
   149  	require.NoError(t, err)
   150  	require.NoError(t, json.Unmarshal(data, actual))
   151  	require.Equal(t, expected, actual)
   152  }
   153  
   154  func TestPermission_ToStackItemFromStackItem(t *testing.T) {
   155  	t.Run("wildcard", func(t *testing.T) {
   156  		p := NewPermission(PermissionWildcard)
   157  		expected := stackitem.NewStruct([]stackitem.Item{
   158  			stackitem.Null{},
   159  			stackitem.Null{},
   160  		})
   161  		CheckToFromStackItem(t, p, expected)
   162  	})
   163  
   164  	t.Run("hash", func(t *testing.T) {
   165  		p := NewPermission(PermissionHash, util.Uint160{1, 2, 3})
   166  		p.Methods = WildStrings{Value: []string{"a"}}
   167  		expected := stackitem.NewStruct([]stackitem.Item{
   168  			stackitem.NewByteArray(util.Uint160{1, 2, 3}.BytesBE()),
   169  			stackitem.NewArray([]stackitem.Item{
   170  				stackitem.NewByteArray([]byte("a")),
   171  			}),
   172  		})
   173  		CheckToFromStackItem(t, p, expected)
   174  	})
   175  
   176  	t.Run("group", func(t *testing.T) {
   177  		pk, _ := keys.NewPrivateKey()
   178  		p := NewPermission(PermissionGroup, pk.PublicKey())
   179  		expected := stackitem.NewStruct([]stackitem.Item{
   180  			stackitem.NewByteArray(pk.PublicKey().Bytes()),
   181  			stackitem.Null{},
   182  		})
   183  		CheckToFromStackItem(t, p, expected)
   184  	})
   185  }
   186  
   187  type Interoperable interface {
   188  	ToStackItem() stackitem.Item
   189  	FromStackItem(stackitem.Item) error
   190  }
   191  
   192  func CheckToFromStackItem(t *testing.T, source Interoperable, expected stackitem.Item) {
   193  	actual := source.ToStackItem()
   194  	require.Equal(t, expected, actual)
   195  	actualSource := reflect.New(reflect.TypeOf(source).Elem()).Interface().(Interoperable)
   196  	require.NoError(t, actualSource.FromStackItem(actual))
   197  	require.Equal(t, source, actualSource)
   198  }
   199  
   200  func TestPermission_FromStackItemErrors(t *testing.T) {
   201  	errCases := map[string]stackitem.Item{
   202  		"not a struct":            stackitem.NewArray([]stackitem.Item{}),
   203  		"invalid length":          stackitem.NewStruct([]stackitem.Item{}),
   204  		"invalid contract type":   stackitem.NewStruct([]stackitem.Item{stackitem.NewArray([]stackitem.Item{}), stackitem.NewBool(false)}),
   205  		"invalid contract length": stackitem.NewStruct([]stackitem.Item{stackitem.NewByteArray([]byte{1, 2, 3}), stackitem.NewBool(false)}),
   206  		"invalid contract pubkey": stackitem.NewStruct([]stackitem.Item{stackitem.NewByteArray(make([]byte, 33)), stackitem.NewBool(false)}),
   207  		"invalid methods type":    stackitem.NewStruct([]stackitem.Item{stackitem.Null{}, stackitem.NewBool(false)}),
   208  		"invalid method name":     stackitem.NewStruct([]stackitem.Item{stackitem.Null{}, stackitem.NewArray([]stackitem.Item{stackitem.NewArray([]stackitem.Item{})})}),
   209  	}
   210  	for name, errCase := range errCases {
   211  		t.Run(name, func(t *testing.T) {
   212  			p := new(Permission)
   213  			require.Error(t, p.FromStackItem(errCase))
   214  		})
   215  	}
   216  }