[#78] owner: check id for validity

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2021-11-15 12:29:47 +03:00 committed by Alex Vanin
parent df6a622c20
commit ca01b83adf
3 changed files with 64 additions and 4 deletions

View file

@ -6,6 +6,8 @@ import (
"fmt" "fmt"
"github.com/mr-tron/base58" "github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/refs"
) )
@ -71,7 +73,7 @@ func (id *ID) Parse(s string) error {
data, err := base58.Decode(s) data, err := base58.Decode(s)
if err != nil { if err != nil {
return fmt.Errorf("could not parse owner.ID from string: %w", err) return fmt.Errorf("could not parse owner.ID from string: %w", err)
} else if len(data) != NEO3WalletSize { } else if !valid(data) {
return errInvalidIDString return errInvalidIDString
} }
@ -80,6 +82,28 @@ func (id *ID) Parse(s string) error {
return nil return nil
} }
// Valid returns true if id is a valid owner id.
// The rules for v2 are the following:
// 1. Must be 25 bytes in length.
// 2. Must have N3 address prefix-byte.
// 3. Last 4 bytes must contain the address checksum.
func (id *ID) Valid() bool {
rawID := id.ToV2().GetValue()
return valid(rawID)
}
func valid(rawID []byte) bool {
if len(rawID) != NEO3WalletSize {
return false
}
if rawID[0] != address.NEO3Prefix {
return false
}
const boundIndex = NEO3WalletSize - 4
return bytes.Equal(rawID[boundIndex:], hash.Checksum(rawID[:boundIndex]))
}
// Marshal marshals ID into a protobuf binary form. // Marshal marshals ID into a protobuf binary form.
func (id *ID) Marshal() ([]byte, error) { func (id *ID) Marshal() ([]byte, error) {
return (*refs.OwnerID)(id).StableMarshal(nil) return (*refs.OwnerID)(id).StableMarshal(nil)

View file

@ -6,6 +6,7 @@ import (
"github.com/mr-tron/base58" "github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util/slice"
"github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/refs"
. "github.com/nspcc-dev/neofs-sdk-go/owner" . "github.com/nspcc-dev/neofs-sdk-go/owner"
ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test" ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test"
@ -20,6 +21,34 @@ func TestIDV2(t *testing.T) {
require.Equal(t, id, NewIDFromV2(idV2)) require.Equal(t, id, NewIDFromV2(idV2))
} }
func TestID_Valid(t *testing.T) {
id := ownertest.GenerateID()
require.True(t, id.Valid())
val := id.ToV2().GetValue()
t.Run("invalid prefix", func(t *testing.T) {
val := slice.Copy(val)
val[0] ^= 0xFF
id := ownertest.GenerateIDFromBytes(val)
require.False(t, id.Valid())
})
t.Run("invalid size", func(t *testing.T) {
val := val[:NEO3WalletSize-1]
id := ownertest.GenerateIDFromBytes(val)
require.False(t, id.Valid())
})
t.Run("invalid checksum", func(t *testing.T) {
val := slice.Copy(val)
val[NEO3WalletSize-1] ^= 0xFF
id := ownertest.GenerateIDFromBytes(val)
require.False(t, id.Valid())
})
}
func TestNewIDFromNeo3Wallet(t *testing.T) { func TestNewIDFromNeo3Wallet(t *testing.T) {
p, err := keys.NewPrivateKey() p, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)

View file

@ -3,6 +3,9 @@ package ownertest
import ( import (
"math/rand" "math/rand"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/nspcc-dev/neofs-sdk-go/owner" "github.com/nspcc-dev/neofs-sdk-go/owner"
) )
@ -10,10 +13,14 @@ import (
// GenerateID returns owner.ID calculated // GenerateID returns owner.ID calculated
// from a random owner.NEO3Wallet. // from a random owner.NEO3Wallet.
func GenerateID() *owner.ID { func GenerateID() *owner.ID {
data := make([]byte, owner.NEO3WalletSize) u := util.Uint160{}
rand.Read(u[:])
rand.Read(data)
addr := address.Uint160ToString(u)
data, err := base58.Decode(addr)
if err != nil {
panic(err)
}
return GenerateIDFromBytes(data) return GenerateIDFromBytes(data)
} }