diff --git a/cmd/neofs-cli/internal/common/eacl.go b/cmd/neofs-cli/internal/common/eacl.go index 7ad07b9475..1b52bd4803 100644 --- a/cmd/neofs-cli/internal/common/eacl.go +++ b/cmd/neofs-cli/internal/common/eacl.go @@ -13,7 +13,7 @@ import ( var errUnsupportedEACLFormat = errors.New("unsupported eACL format") // ReadEACL reads extended ACL table from eaclPath. -func ReadEACL(cmd *cobra.Command, eaclPath string) *eacl.Table { +func ReadEACL(cmd *cobra.Command, eaclPath string) eacl.Table { _, err := os.Stat(eaclPath) // check if `eaclPath` is an existing file if err != nil { ExitOnErr(cmd, "", errors.New("incorrect path to file with EACL")) @@ -24,25 +24,25 @@ func ReadEACL(cmd *cobra.Command, eaclPath string) *eacl.Table { data, err := os.ReadFile(eaclPath) ExitOnErr(cmd, "can't read file with EACL: %w", err) - table := eacl.NewTable() - - if err = table.UnmarshalJSON(data); err == nil { + table, err := eacl.UnmarshalJSON(data) + if err == nil { validateAndFixEACLVersion(table) PrintVerbose(cmd, "Parsed JSON encoded EACL table") return table } - if err = table.Unmarshal(data); err == nil { + table, err = eacl.Unmarshal(data) + if err == nil { validateAndFixEACLVersion(table) PrintVerbose(cmd, "Parsed binary encoded EACL table") return table } ExitOnErr(cmd, "", errUnsupportedEACLFormat) - return nil + return eacl.Table{} } -func validateAndFixEACLVersion(table *eacl.Table) { +func validateAndFixEACLVersion(table eacl.Table) { if !version.IsValid(table.Version()) { table.SetVersion(versionSDK.Current()) } diff --git a/cmd/neofs-cli/modules/acl/extended/create.go b/cmd/neofs-cli/modules/acl/extended/create.go index 92d4fc2dbd..8f72eadf02 100644 --- a/cmd/neofs-cli/modules/acl/extended/create.go +++ b/cmd/neofs-cli/modules/acl/extended/create.go @@ -88,8 +88,8 @@ func createEACL(cmd *cobra.Command, _ []string) { os.Exit(1) } - tb := eacl.NewTable() - common.ExitOnErr(cmd, "unable to parse provided rules: %w", util.ParseEACLRules(tb, rules)) + var tb eacl.Table + common.ExitOnErr(cmd, "unable to parse provided rules: %w", util.ParseEACLRules(&tb, rules)) err = util.ValidateEACLTable(tb) common.ExitOnErr(cmd, "table validation: %w", err) diff --git a/cmd/neofs-cli/modules/bearer/create.go b/cmd/neofs-cli/modules/bearer/create.go index 9177a84a29..da37f92696 100644 --- a/cmd/neofs-cli/modules/bearer/create.go +++ b/cmd/neofs-cli/modules/bearer/create.go @@ -108,11 +108,11 @@ func createToken(cmd *cobra.Command, _ []string) { eaclPath, _ := cmd.Flags().GetString(eaclFlag) if eaclPath != "" { - table := eaclSDK.NewTable() raw, err := os.ReadFile(eaclPath) common.ExitOnErr(cmd, "can't read extended ACL file: %w", err) - common.ExitOnErr(cmd, "can't parse extended ACL: %w", json.Unmarshal(raw, table)) - b.SetEACLTable(*table) + table, err := eaclSDK.UnmarshalJSON(raw) + common.ExitOnErr(cmd, "can't parse extended ACL: %w", err) + b.SetEACLTable(table) } var data []byte diff --git a/cmd/neofs-cli/modules/container/set_eacl.go b/cmd/neofs-cli/modules/container/set_eacl.go index dcb7ca4c96..51dd119f07 100644 --- a/cmd/neofs-cli/modules/container/set_eacl.go +++ b/cmd/neofs-cli/modules/container/set_eacl.go @@ -86,7 +86,7 @@ Container ID in EACL table will be substituted with ID from the CLI.`, var setEACLPrm internalclient.SetEACLPrm setEACLPrm.SetClient(cli) - setEACLPrm.SetTable(*eaclTable) + setEACLPrm.SetTable(eaclTable) setEACLPrm.SetPrivateKey(*pk) if tok != nil { diff --git a/cmd/neofs-cli/modules/util/acl.go b/cmd/neofs-cli/modules/util/acl.go index 7c7bd8eb6b..ec12e51663 100644 --- a/cmd/neofs-cli/modules/util/acl.go +++ b/cmd/neofs-cli/modules/util/acl.go @@ -209,8 +209,8 @@ func parseEACLTable(tb *eacl.Table, args []string) error { return errors.New("at least 2 arguments must be provided") } - var action eacl.Action - if !action.DecodeString(strings.ToUpper(args[0])) { + action, ok := eacl.ActionFromString(strings.ToUpper(args[0])) + if !ok { return errors.New("invalid action (expected 'allow' or 'deny')") } @@ -226,29 +226,37 @@ func parseEACLTable(tb *eacl.Table, args []string) error { r.SetAction(action) + records := make([]eacl.Record, 0, len(ops)) + for _, op := range ops { - r := *r - r.SetOperation(op) - tb.AddRecord(&r) + var record eacl.Record + r.CopyTo(&record) + + record.SetOperation(op) + records = append(records, record) } + tb.SetRecords(records) + return nil } -func parseEACLRecord(args []string) (*eacl.Record, error) { - r := new(eacl.Record) +func parseEACLRecord(args []string) (eacl.Record, error) { + var filters []eacl.Filter + var targets []eacl.Target + for i := range args { ss := strings.SplitN(args[i], ":", 2) switch prefix := strings.ToLower(ss[0]); prefix { case "req", "obj": // filters if len(ss) != 2 { - return nil, fmt.Errorf("invalid filter or target: %s", args[i]) + return eacl.Record{}, fmt.Errorf("invalid filter or target: %s", args[i]) } key, value, op, err := parseKVWithOp(ss[1]) if err != nil { - return nil, fmt.Errorf("invalid filter key-value pair %s: %w", ss[1], err) + return eacl.Record{}, fmt.Errorf("invalid filter key-value pair %s: %w", ss[1], err) } typ := eacl.HeaderFromRequest @@ -256,27 +264,31 @@ func parseEACLRecord(args []string) (*eacl.Record, error) { typ = eacl.HeaderFromObject } - r.AddFilter(typ, op, key, value) + filters = append(filters, eacl.ConstructFilter(typ, key, op, value)) case "others", "system", "user", "pubkey": // targets var err error - var pubs []ecdsa.PublicKey + var pubs []*ecdsa.PublicKey if len(ss) == 2 { pubs, err = parseKeyList(ss[1]) if err != nil { - return nil, err + return eacl.Record{}, err } } - var role eacl.Role if prefix != "pubkey" { - role, err = eaclRoleFromString(prefix) + role, err := eaclRoleFromString(prefix) if err != nil { - return nil, err + return eacl.Record{}, err } + + targets = append(targets, eacl.NewTargetByRole(role)) + continue } - eacl.AddFormedTarget(r, role, pubs...) + var target eacl.Target + eacl.SetTargetECDSAKeys(&target, pubs...) + targets = append(targets, target) case "address": // targets var ( err error @@ -284,23 +296,21 @@ func parseEACLRecord(args []string) (*eacl.Record, error) { ) if len(ss) != 2 { - return nil, fmt.Errorf("invalid address: %s", args[i]) + return eacl.Record{}, fmt.Errorf("invalid address: %s", args[i]) } accounts, err = parseAccountList(ss[1]) if err != nil { - return nil, err + return eacl.Record{}, err } - t := eacl.NewTarget() - t.SetAccounts(accounts) - eacl.AddRecordTarget(r, t) + targets = append(targets, eacl.NewTargetByAccounts(accounts)) default: - return nil, fmt.Errorf("invalid prefix: %s", ss[0]) + return eacl.Record{}, fmt.Errorf("invalid prefix: %s", ss[0]) } } - return r, nil + return eacl.ConstructRecord(eacl.ActionUnspecified, eacl.OperationUnspecified, targets, filters...), nil } func parseKVWithOp(s string) (string, string, eacl.Match, error) { @@ -356,8 +366,8 @@ func validateDecimal(s string) bool { // eaclRoleFromString parses eacl.Role from string. func eaclRoleFromString(s string) (eacl.Role, error) { - var r eacl.Role - if !r.DecodeString(strings.ToUpper(s)) { + r, ok := eacl.RoleFromString(strings.ToUpper(s)) + if !ok { return r, fmt.Errorf("unexpected role %s", s) } @@ -365,9 +375,9 @@ func eaclRoleFromString(s string) (eacl.Role, error) { } // parseKeyList parses list of hex-encoded public keys separated by comma. -func parseKeyList(s string) ([]ecdsa.PublicKey, error) { +func parseKeyList(s string) ([]*ecdsa.PublicKey, error) { ss := strings.Split(s, ",") - pubs := make([]ecdsa.PublicKey, len(ss)) + pubs := make([]*ecdsa.PublicKey, len(ss)) for i := range ss { st := strings.TrimPrefix(ss[i], "0x") pub, err := keys.NewPublicKeyFromString(st) @@ -375,7 +385,7 @@ func parseKeyList(s string) ([]ecdsa.PublicKey, error) { return nil, fmt.Errorf("invalid public key '%s': %w", ss[i], err) } - pubs[i] = ecdsa.PublicKey(*pub) + pubs[i] = (*ecdsa.PublicKey)(pub) } return pubs, nil @@ -402,9 +412,10 @@ func parseAccountList(s string) ([]user.ID, error) { func eaclOperationsFromString(s string) ([]eacl.Operation, error) { ss := strings.Split(s, ",") ops := make([]eacl.Operation, len(ss)) + var ok bool for i := range ss { - if !ops[i].DecodeString(strings.ToUpper(ss[i])) { + if ops[i], ok = eacl.OperationFromString(strings.ToUpper(ss[i])); !ok { return nil, fmt.Errorf("invalid operation: %s", ss[i]) } } @@ -414,7 +425,7 @@ func eaclOperationsFromString(s string) ([]eacl.Operation, error) { // ValidateEACLTable validates eACL table: // - eACL table must not modify [eacl.RoleSystem] access. -func ValidateEACLTable(t *eacl.Table) error { +func ValidateEACLTable(t eacl.Table) error { var b big.Int for _, record := range t.Records() { for _, target := range record.Targets() { diff --git a/cmd/neofs-cli/modules/util/acl_test.go b/cmd/neofs-cli/modules/util/acl_test.go index 00adad1f7b..dc2a12e918 100644 --- a/cmd/neofs-cli/modules/util/acl_test.go +++ b/cmd/neofs-cli/modules/util/acl_test.go @@ -90,7 +90,7 @@ func TestValidateEACL(t *testing.T) { tb := anyValidEACL() tb.AddRecord(&r) - err := ValidateEACLTable(&tb) + err := ValidateEACLTable(tb) require.ErrorContains(t, err, "non-empty value in absence filter") r = eacl.Record{} @@ -98,7 +98,7 @@ func TestValidateEACL(t *testing.T) { tb = anyValidEACL() tb.AddRecord(&r) - err = ValidateEACLTable(&tb) + err = ValidateEACLTable(tb) require.NoError(t, err) }) @@ -124,7 +124,7 @@ func TestValidateEACL(t *testing.T) { tb := anyValidEACL() tb.AddRecord(&r) - err := ValidateEACLTable(&tb) + err := ValidateEACLTable(tb) if tc.ok { require.NoError(t, err, [2]any{m, tc}) } else { diff --git a/cmd/neofs-node/object.go b/cmd/neofs-node/object.go index 4a63815dc2..ea52fbf9fc 100644 --- a/cmd/neofs-node/object.go +++ b/cmd/neofs-node/object.go @@ -5,7 +5,6 @@ import ( "context" "errors" "fmt" - "strings" lru "github.com/hashicorp/golang-lru/v2" "github.com/nspcc-dev/neofs-api-go/v2/object" @@ -750,8 +749,7 @@ func (n netmapSourceWithNodes) ServerInContainer(cID cid.ID) (bool, error) { return true }) if err != nil { - // https://github.com/nspcc-dev/neofs-sdk-go/pull/615 - if strings.Contains(err.Error(), "not enough nodes to SELECT from") { + if errors.Is(err, netmapsdk.ErrNotEnoughNodes) { return false, nil } diff --git a/go.mod b/go.mod index cac65f5647..3feedea2e4 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/nspcc-dev/neo-go v0.106.3 github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 github.com/nspcc-dev/neofs-contract v0.20.0 - github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240807160341-3528eb5bb1cc + github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240809202351-256513c1b29b github.com/nspcc-dev/tzhash v1.8.0 github.com/olekukonko/tablewriter v0.0.5 github.com/panjf2000/ants/v2 v2.9.0 diff --git a/go.sum b/go.sum index 2768e9afd1..8a219874f3 100644 --- a/go.sum +++ b/go.sum @@ -135,8 +135,8 @@ github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 h1:ar github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8= github.com/nspcc-dev/neofs-contract v0.20.0 h1:ARE/3mSN+P9qi/10NBsf7QyPiYrvnxeEgYUN13vHRlo= github.com/nspcc-dev/neofs-contract v0.20.0/go.mod h1:YxtKYE/5cMNiqwWcQWzeizbB9jizauLni+p8wXxfhsQ= -github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240807160341-3528eb5bb1cc h1:WjVjs1vGILIVXC0lhJGWy2ek5FfT9S0HCOite/4tsks= -github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240807160341-3528eb5bb1cc/go.mod h1:ewV84r1NACvoBfbKQKzRLUun+Xn5+z9JVqsuCVgv9xI= +github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240809202351-256513c1b29b h1:/7jXQP5pf+M0kRFC1gg5GEdTPkvotpMHxjSXIbMZaGQ= +github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240809202351-256513c1b29b/go.mod h1:ewV84r1NACvoBfbKQKzRLUun+Xn5+z9JVqsuCVgv9xI= github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM= github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc= github.com/nspcc-dev/tzhash v1.8.0 h1:pJvzME2mZzP/h5rcy/Wb6amT9FJBFeKbJ3HEnWEeUpY= diff --git a/pkg/innerring/processors/container/process_eacl.go b/pkg/innerring/processors/container/process_eacl.go index 0f86fbb86c..650572f783 100644 --- a/pkg/innerring/processors/container/process_eacl.go +++ b/pkg/innerring/processors/container/process_eacl.go @@ -34,9 +34,7 @@ func (cp *Processor) checkSetEACL(e container.SetEACL) error { binTable := e.Table() // unmarshal table - table := eacl.NewTable() - - err := table.Unmarshal(binTable) + table, err := eacl.Unmarshal(binTable) if err != nil { return fmt.Errorf("invalid binary table: %w", err) } @@ -99,7 +97,7 @@ func (cp *Processor) approveSetEACL(e container.SetEACL) { } } -func validateEACL(t *eacl.Table) error { +func validateEACL(t eacl.Table) error { var b big.Int for _, record := range t.Records() { for _, target := range record.Targets() { diff --git a/pkg/innerring/processors/container/process_eacl_test.go b/pkg/innerring/processors/container/process_eacl_test.go index e3f0d6b768..309a26e49a 100644 --- a/pkg/innerring/processors/container/process_eacl_test.go +++ b/pkg/innerring/processors/container/process_eacl_test.go @@ -20,7 +20,7 @@ func TestValidateEACL(t *testing.T) { tb := anyValidEACL() tb.AddRecord(&r) - err := validateEACL(&tb) + err := validateEACL(tb) require.ErrorContains(t, err, "non-empty value in absence filter") r = eacl.Record{} @@ -28,7 +28,7 @@ func TestValidateEACL(t *testing.T) { tb = anyValidEACL() tb.AddRecord(&r) - err = validateEACL(&tb) + err = validateEACL(tb) require.NoError(t, err) }) @@ -54,7 +54,7 @@ func TestValidateEACL(t *testing.T) { tb := anyValidEACL() tb.AddRecord(&r) - err := validateEACL(&tb) + err := validateEACL(tb) if tc.ok { require.NoError(t, err, [2]any{m, tc}) } else { diff --git a/pkg/local_object_storage/metabase/db_test.go b/pkg/local_object_storage/metabase/db_test.go index 7b0a0eb0a4..f1b4b10120 100644 --- a/pkg/local_object_storage/metabase/db_test.go +++ b/pkg/local_object_storage/metabase/db_test.go @@ -1,13 +1,13 @@ package meta_test import ( + "crypto/rand" "os" "strconv" "testing" meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase" "github.com/nspcc-dev/neofs-sdk-go/checksum" - checksumtest "github.com/nspcc-dev/neofs-sdk-go/checksum/test" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test" "github.com/nspcc-dev/neofs-sdk-go/object" @@ -16,7 +16,6 @@ import ( oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test" usertest "github.com/nspcc-dev/neofs-sdk-go/user/test" "github.com/nspcc-dev/neofs-sdk-go/version" - "github.com/nspcc-dev/tzhash/tz" "github.com/stretchr/testify/require" ) @@ -76,12 +75,14 @@ func generateObjectWithCID(t testing.TB, cnr cid.ID) *object.Object { ver.SetMajor(2) ver.SetMinor(1) - csum := checksumtest.Checksum() - - var csumTZ checksum.Checksum - csumTZ.SetTillichZemor(tz.Sum(csum.Value())) + payload := make([]byte, 10) + _, err := rand.Read(payload) + require.NoError(t, err) - payload := []byte{1, 2, 3, 4, 5} + csum, err := checksum.NewFromData(checksum.SHA256, payload) + require.NoError(t, err) + csumTZ, err := checksum.NewFromData(checksum.TillichZemor, payload) + require.NoError(t, err) obj := object.New() obj.SetID(oidtest.ID()) diff --git a/pkg/local_object_storage/metabase/select_test.go b/pkg/local_object_storage/metabase/select_test.go index d8dea30eea..a607d4c99e 100644 --- a/pkg/local_object_storage/metabase/select_test.go +++ b/pkg/local_object_storage/metabase/select_test.go @@ -376,32 +376,40 @@ func TestDB_SelectPayloadHash(t *testing.T) { cs, _ := raw1.PayloadChecksum() payloadHash := [sha256.Size]byte(cs.Value()) - fs := objectSDK.SearchFilters{} - fs.AddPayloadHashFilter(objectSDK.MatchStringEqual, payloadHash) + t.Run("equal filter", func(t *testing.T) { + fs := objectSDK.SearchFilters{} + fs.AddPayloadHashFilter(objectSDK.MatchStringEqual, payloadHash) - testSelect(t, db, cnr, fs, object.AddressOf(raw1)) + testSelect(t, db, cnr, fs, object.AddressOf(raw1)) + }) - fs = objectSDK.SearchFilters{} - fs.AddFilter(objectSDK.FilterPayloadChecksum, - hex.EncodeToString(payloadHash[:len(payloadHash)-1]), - objectSDK.MatchCommonPrefix) + t.Run("common prefix filter", func(t *testing.T) { + fs := objectSDK.SearchFilters{} + fs.AddFilter(objectSDK.FilterPayloadChecksum, + hex.EncodeToString(payloadHash[:len(payloadHash)-1]), + objectSDK.MatchCommonPrefix) - testSelect(t, db, cnr, fs, object.AddressOf(raw1)) + testSelect(t, db, cnr, fs, object.AddressOf(raw1)) + }) - fs = objectSDK.SearchFilters{} - fs.AddPayloadHashFilter(objectSDK.MatchStringNotEqual, payloadHash) + t.Run("not equal filter", func(t *testing.T) { + fs := objectSDK.SearchFilters{} + fs.AddPayloadHashFilter(objectSDK.MatchStringNotEqual, payloadHash) - testSelect(t, db, cnr, fs, object.AddressOf(raw2)) + testSelect(t, db, cnr, fs, object.AddressOf(raw2)) + }) - fs = objectSDK.SearchFilters{} - fs.AddFilter(objectSDK.FilterPayloadChecksum, - "", - objectSDK.MatchNotPresent) + t.Run("not present filter", func(t *testing.T) { + fs := objectSDK.SearchFilters{} + fs.AddFilter(objectSDK.FilterPayloadChecksum, + "", + objectSDK.MatchNotPresent) - testSelect(t, db, cnr, fs) + testSelect(t, db, cnr, fs) + }) t.Run("invalid hashes", func(t *testing.T) { - fs = objectSDK.SearchFilters{} + fs := objectSDK.SearchFilters{} otherHash := payloadHash otherHash[0]++ fs.AddPayloadHashFilter(objectSDK.MatchStringNotEqual, otherHash) diff --git a/pkg/morph/client/container/eacl.go b/pkg/morph/client/container/eacl.go index 2111c4e4b9..984707956b 100644 --- a/pkg/morph/client/container/eacl.go +++ b/pkg/morph/client/container/eacl.go @@ -71,10 +71,11 @@ func (c *Client) GetEACL(cnr cid.ID) (*container.EACL, error) { var res container.EACL - res.Value = eacl.NewTable() - if err = res.Value.Unmarshal(rawEACL); err != nil { + t, err := eacl.Unmarshal(rawEACL) + if err != nil { return nil, err } + res.Value = &t if len(binToken) > 0 { res.Session = new(session.Container)