diff --git a/CHANGELOG.md b/CHANGELOG.md index 02254ab..1e9d098 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog -This is the changelog for NeoFS API +This is the changelog for NeoFS-API-Go + +## [0.6.0] - 2020-04-03 + +### Added + +- `RequestType` for object service requests +- `Type()` function in `Request` interface + +### Changed + +- Synced proto files with `neofs-api v0.6.0` ## [0.5.0] - 2020-03-31 @@ -217,3 +228,4 @@ Initial public release [0.4.1]: https://github.com/nspcc-dev/neofs-api-go/compare/v0.4.0...v0.4.1 [0.4.2]: https://github.com/nspcc-dev/neofs-api-go/compare/v0.4.1...v0.4.2 [0.5.0]: https://github.com/nspcc-dev/neofs-api-go/compare/v0.4.2...v0.5.0 +[0.6.0]: https://github.com/nspcc-dev/neofs-api-go/compare/v0.5.0...v0.6.0 diff --git a/Makefile b/Makefile index 84583ff..9b02a6e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PROTO_VERSION=v0.5.0 +PROTO_VERSION=v0.6.0 PROTO_URL=https://github.com/nspcc-dev/neofs-api/archive/$(PROTO_VERSION).tar.gz B=\033[0;1m diff --git a/acl/types.pb.go b/acl/types.pb.go new file mode 100644 index 0000000..bcbd199 Binary files /dev/null and b/acl/types.pb.go differ diff --git a/acl/types.proto b/acl/types.proto new file mode 100644 index 0000000..f20423f --- /dev/null +++ b/acl/types.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; +package acl; +option go_package = "github.com/nspcc-dev/neofs-api-go/acl"; +option csharp_namespace = "NeoFS.API.Acl"; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; +option (gogoproto.stable_marshaler_all) = true; + +// Target of the access control rule in access control list. +enum Target { + // Unknown target, default value. + Unknown = 0; + + // User target rule is applied if sender is the owner of the container. + User = 1; + + // System target rule is applied if sender is the storage node within the + // container or inner ring node. + System = 2; + + // Others target rule is applied if sender is not user or system target. + Others = 3; + + // PubKey target rule is applied if sender has public key provided in + // extended ACL. + PubKey = 4; +} diff --git a/container/service.go b/container/service.go index 8eb9ba6..2f36dc1 100644 --- a/container/service.go +++ b/container/service.go @@ -31,9 +31,11 @@ func (m *PutRequest) PrepareData() ([]byte, error) { err error buf = new(bytes.Buffer) capBytes = make([]byte, 8) + aclBytes = make([]byte, 4) ) binary.BigEndian.PutUint64(capBytes, m.Capacity) + binary.BigEndian.PutUint32(capBytes, m.BasicACL) if _, err = buf.Write(m.MessageID.Bytes()); err != nil { return nil, errors.Wrap(err, "could not write message id") @@ -45,6 +47,8 @@ func (m *PutRequest) PrepareData() ([]byte, error) { return nil, errors.Wrap(err, "could not marshal placement") } else if _, err = buf.Write(data); err != nil { return nil, errors.Wrap(err, "could not write placement") + } else if _, err = buf.Write(aclBytes); err != nil { + return nil, errors.Wrap(err, "could not write basic acl") } return buf.Bytes(), nil diff --git a/container/service.pb.go b/container/service.pb.go index 8698925..6131254 100644 Binary files a/container/service.pb.go and b/container/service.pb.go differ diff --git a/container/service.proto b/container/service.proto index bccf924..7df2c66 100644 --- a/container/service.proto +++ b/container/service.proto @@ -42,8 +42,8 @@ message PutRequest { // Rules define storage policy for the object inside the container. netmap.PlacementRule rules = 4 [(gogoproto.nullable) = false]; - // Container ACL. - AccessGroup Group = 5 [(gogoproto.nullable) = false]; + // BasicACL of the container. + uint32 BasicACL = 5; // RequestMetaHeader contains information about request meta headers (should be embedded into message) service.RequestMetaHeader Meta = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; diff --git a/container/types.go b/container/types.go index 21fc0d1..e358e6d 100644 --- a/container/types.go +++ b/container/types.go @@ -11,19 +11,6 @@ import ( "github.com/pkg/errors" ) -// AccessMode is a container access mode type. -type AccessMode uint32 - -const ( - // AccessModeRead is a read access mode. - AccessModeRead AccessMode = 1 << iota - // AccessModeWrite is a write access mode. - AccessModeWrite -) - -// AccessModeReadWrite is a read/write container access mode. -const AccessModeReadWrite = AccessModeRead | AccessModeWrite - var ( _ internal.Custom = (*Container)(nil) @@ -31,8 +18,8 @@ var ( emptyOwner = (OwnerID{}).Bytes() ) -// New creates new user container based on capacity, OwnerID and PlacementRules. -func New(cap uint64, owner OwnerID, rules netmap.PlacementRule) (*Container, error) { +// New creates new user container based on capacity, OwnerID, ACL and PlacementRules. +func New(cap uint64, owner OwnerID, acl uint32, rules netmap.PlacementRule) (*Container, error) { if bytes.Equal(owner[:], emptyOwner) { return nil, refs.ErrEmptyOwner } else if cap == 0 { @@ -49,6 +36,7 @@ func New(cap uint64, owner OwnerID, rules netmap.PlacementRule) (*Container, err Salt: UUID(salt), Capacity: cap, Rules: rules, + BasicACL: acl, }, nil } @@ -90,7 +78,7 @@ func NewTestContainer() (*Container, error) { if err != nil { return nil, err } - return New(100, owner, netmap.PlacementRule{ + return New(100, owner, 0xFFFFFFFF, netmap.PlacementRule{ ReplFactor: 2, SFGroups: []netmap.SFGroup{ { diff --git a/container/types.pb.go b/container/types.pb.go index bfb7fa7..391656c 100644 Binary files a/container/types.pb.go and b/container/types.pb.go differ diff --git a/container/types.proto b/container/types.proto index a0d035d..dc79bd3 100644 --- a/container/types.proto +++ b/container/types.proto @@ -18,18 +18,7 @@ message Container { uint64 Capacity = 3; // Rules define storage policy for the object inside the container. netmap.PlacementRule Rules = 4 [(gogoproto.nullable) = false]; - // Container ACL. - AccessControlList List = 5 [(gogoproto.nullable) = false]; -} - -message AccessGroup { - // Group access mode. - uint32 AccessMode = 1; - // Group members. - repeated bytes UserGroup = 2 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; -} - -message AccessControlList { - // List of access groups. - repeated AccessGroup List = 1 [(gogoproto.nullable) = false]; + // BasicACL with access control rules for owner, system, others and + // permission bits for bearer token and extended ACL. + uint32 BasicACL = 5; } diff --git a/container/types_test.go b/container/types_test.go index 1ccc00b..fddccb3 100644 --- a/container/types_test.go +++ b/container/types_test.go @@ -36,7 +36,7 @@ func TestCID(t *testing.T) { owner, err := refs.NewOwnerID(&key.PublicKey) require.NoError(t, err) - c1, err := New(10, owner, rules) + c1, err := New(10, owner, 0xDEADBEEF, rules) require.NoError(t, err) data, err := proto.Marshal(c1) @@ -55,23 +55,3 @@ func TestCID(t *testing.T) { require.Equal(t, cid1, cid2) }) } - -func TestAccessMode(t *testing.T) { - t.Run("read access to read/write mode", func(t *testing.T) { - require.Equal(t, AccessModeRead, AccessModeReadWrite&AccessModeRead) - }) - - t.Run("write access to read/write mode", func(t *testing.T) { - require.Equal(t, AccessModeWrite, AccessModeReadWrite&AccessModeWrite) - }) - - t.Run("read(write) access to write(read) mode", func(t *testing.T) { - require.Zero(t, AccessModeRead&AccessModeWrite) - }) - - t.Run("access to same mode", func(t *testing.T) { - require.Equal(t, AccessModeWrite, AccessModeWrite&AccessModeWrite) - require.Equal(t, AccessModeRead, AccessModeRead&AccessModeRead) - require.Equal(t, AccessModeReadWrite, AccessModeReadWrite&AccessModeReadWrite) - }) -} diff --git a/docs/acl.md b/docs/acl.md new file mode 100644 index 0000000..38f328b --- /dev/null +++ b/docs/acl.md @@ -0,0 +1,62 @@ +# Protocol Documentation + + +## Table of Contents + +- [acl/types.proto](#acl/types.proto) + + + +- [Scalar Value Types](#scalar-value-types) + + + + +
+ +## acl/types.proto + + + + + + + + + +### Target +Target of the access control rule in access control list. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| Unknown | 0 | Unknown target, default value. | +| User | 1 | User target rule is applied if sender is the owner of the container. | +| System | 2 | System target rule is applied if sender is the storage node within the container or inner ring node. | +| Others | 3 | Others target rule is applied if sender is not user or system target. | +| PubKey | 4 | PubKey target rule is applied if sender has public key provided in extended ACL. | + + + + + + +## Scalar Value Types + +| .proto Type | Notes | C++ Type | Java Type | Python Type | +| ----------- | ----- | -------- | --------- | ----------- | +| double | | double | double | float | +| float | | float | float | float | +| int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | +| int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | +| uint32 | Uses variable-length encoding. | uint32 | int | int/long | +| uint64 | Uses variable-length encoding. | uint64 | long | int/long | +| sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | +| sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | +| fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | +| fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | +| sfixed32 | Always four bytes. | int32 | int | int | +| sfixed64 | Always eight bytes. | int64 | long | int/long | +| bool | | bool | boolean | boolean | +| string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | +| bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | + diff --git a/docs/container.md b/docs/container.md index 6693980..f0188ca 100644 --- a/docs/container.md +++ b/docs/container.md @@ -21,8 +21,6 @@ - [container/types.proto](#container/types.proto) - Messages - - [AccessControlList](#container.AccessControlList) - - [AccessGroup](#container.AccessGroup) - [Container](#container.Container) @@ -166,7 +164,7 @@ via consensus in inner ring nodes | Capacity | [uint64](#uint64) | | Capacity defines amount of data that can be stored in the container (doesn't used for now). | | OwnerID | [bytes](#bytes) | | OwnerID is a wallet address | | rules | [netmap.PlacementRule](#netmap.PlacementRule) | | Rules define storage policy for the object inside the container. | -| Group | [AccessGroup](#container.AccessGroup) | | Container ACL. | +| BasicACL | [uint32](#uint32) | | BasicACL of the container. | | Meta | [service.RequestMetaHeader](#service.RequestMetaHeader) | | RequestMetaHeader contains information about request meta headers (should be embedded into message) | | Verify | [service.RequestVerificationHeader](#service.RequestVerificationHeader) | | RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message) | @@ -196,29 +194,6 @@ via consensus in inner ring nodes - - -### Message AccessControlList - - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| List | [AccessGroup](#container.AccessGroup) | repeated | List of access groups. | - - - - -### Message AccessGroup - - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| AccessMode | [uint32](#uint32) | | Group access mode. | -| UserGroup | [bytes](#bytes) | repeated | Group members. | - - ### Message Container @@ -231,7 +206,7 @@ The Container service definition. | Salt | [bytes](#bytes) | | Salt is a nonce for unique container id calculation. | | Capacity | [uint64](#uint64) | | Capacity defines amount of data that can be stored in the container (doesn't used for now). | | Rules | [netmap.PlacementRule](#netmap.PlacementRule) | | Rules define storage policy for the object inside the container. | -| List | [AccessControlList](#container.AccessControlList) | | Container ACL. | +| BasicACL | [uint32](#uint32) | | BasicACL with access control rules for owner, system, others and permission bits for bearer token and extended ACL. | diff --git a/object/service.go b/object/service.go index 589bd95..3a2ca08 100644 --- a/object/service.go +++ b/object/service.go @@ -28,12 +28,13 @@ type ( Token = session.Token // Request defines object rpc requests. - // All object operations must have TTL, Epoch, Container ID and + // All object operations must have TTL, Epoch, Type, Container ID and // permission of usage previous network map. Request interface { service.MetaHeader CID() CID + Type() RequestType AllowPreviousNetMap() bool } ) @@ -169,3 +170,24 @@ func (m *GetRangeRequest) AllowPreviousNetMap() bool { return false } // AllowPreviousNetMap returns permission to use previous network map in object get range hash request. func (m *GetRangeHashRequest) AllowPreviousNetMap() bool { return false } + +// Type returns type of the object put request. +func (m *PutRequest) Type() RequestType { return RequestPut } + +// Type returns type of the object get request. +func (m *GetRequest) Type() RequestType { return RequestGet } + +// Type returns type of the object head request. +func (m *HeadRequest) Type() RequestType { return RequestHead } + +// Type returns type of the object search request. +func (m *SearchRequest) Type() RequestType { return RequestSearch } + +// Type returns type of the object delete request. +func (m *DeleteRequest) Type() RequestType { return RequestDelete } + +// Type returns type of the object get range request. +func (m *GetRangeRequest) Type() RequestType { return RequestRange } + +// Type returns type of the object get range hash request. +func (m *GetRangeHashRequest) Type() RequestType { return RequestRangeHash } diff --git a/object/service_test.go b/object/service_test.go index f06e557..46213e2 100644 --- a/object/service_test.go +++ b/object/service_test.go @@ -18,11 +18,22 @@ func TestRequest(t *testing.T) { &GetRangeHashRequest{}, } + types := []RequestType{ + RequestPut, + RequestGet, + RequestHead, + RequestSearch, + RequestDelete, + RequestRange, + RequestRangeHash, + } + for i := range cases { v := cases[i] t.Run(fmt.Sprintf("%T", v), func(t *testing.T) { require.NotPanics(t, func() { v.CID() }) + require.Equal(t, types[i], v.Type()) }) } } diff --git a/object/types.go b/object/types.go index de909a8..cde1f25 100644 --- a/object/types.go +++ b/object/types.go @@ -28,7 +28,10 @@ type ( PRead(ctx context.Context, addr refs.Address, rng Range) ([]byte, error) } - headerType int + // RequestType of the object service requests. + RequestType int + + headerType int ) const ( @@ -71,12 +74,52 @@ const ( PublicKeyHdr ) +const ( + _ RequestType = iota + // RequestPut is a type for object put request. + RequestPut + // RequestGet is a type for object get request. + RequestGet + // RequestHead is a type for object head request. + RequestHead + // RequestSearch is a type for object search request. + RequestSearch + // RequestRange is a type for object range request. + RequestRange + // RequestRangeHash is a type for object hash range request. + RequestRangeHash + // RequestDelete is a type for object delete request. + RequestDelete +) + var ( _ internal.Custom = (*Object)(nil) emptyObject = new(Object).Bytes() ) +// String returns printable name of the request type. +func (s RequestType) String() string { + switch s { + case RequestPut: + return "PUT" + case RequestGet: + return "GET" + case RequestHead: + return "HEAD" + case RequestSearch: + return "SEARCH" + case RequestRange: + return "RANGE" + case RequestRangeHash: + return "RANGE_HASH" + case RequestDelete: + return "DELETE" + default: + return "UNKNOWN" + } +} + // Bytes returns marshaled object in a binary format. func (m Object) Bytes() []byte { data, _ := m.Marshal(); return data }