diff --git a/pkg/services/object/acl/basic_helper.go b/pkg/services/object/acl/basic_helper.go new file mode 100644 index 000000000..c99829aaa --- /dev/null +++ b/pkg/services/object/acl/basic_helper.go @@ -0,0 +1,180 @@ +package acl + +import ( + "github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl" +) + +// wrapper around basic ACL to provide easy access to basic ACL fields +type basicACLHelper uint32 + +const ( + reservedBitNumber = 2 // first left bits are reserved + stickyBitPos = reservedBitNumber // X-bit after reserved bits + finalBitPos = stickyBitPos + 1 // F-bit after X-bit +) + +const ( + opOffset = finalBitPos + 1 // offset of operation bits + bitsPerOp = 4 // number of bits per operation + opNumber = 7 // number of operation bit sections +) + +const ( + bitUser uint8 = iota + bitSystem + bitOthers + bitBearer +) + +const leftACLBitPos = opOffset + bitsPerOp*opNumber - 1 + +var ( + order = map[eacl.Operation]uint8{ + eacl.OperationRangeHash: 0, + eacl.OperationRange: 1, + eacl.OperationSearch: 2, + eacl.OperationDelete: 3, + eacl.OperationPut: 4, + eacl.OperationHead: 5, + eacl.OperationGet: 6, + } +) + +// returns true if n-th left bit is set (starting at 0). +func isLeftBitSet(value basicACLHelper, n uint8) bool { + bitMask := basicACLHelper(1 << (leftACLBitPos - n)) + return bitMask != 0 && value&bitMask == bitMask +} + +// sets n-th left bit (starting at 0). +func setLeftBit(value *basicACLHelper, n uint8) { + *value |= basicACLHelper(1 << (leftACLBitPos - n)) +} + +// resets n-th left bit (starting at 0). +func resetLeftBit(value *basicACLHelper, n uint8) { + *value &= ^basicACLHelper(1 << (leftACLBitPos - n)) +} + +// Final returns true if final option is enabled in ACL. +func (a basicACLHelper) Final() bool { + return isLeftBitSet(a, finalBitPos) +} + +// SetFinal enables final option in ACL. +func (a *basicACLHelper) SetFinal() { + setLeftBit(a, finalBitPos) +} + +// ResetFinal disables final option in ACL. +func (a *basicACLHelper) ResetFinal() { + resetLeftBit(a, finalBitPos) +} + +// Sticky returns true if sticky option is enabled in ACL. +func (a basicACLHelper) Sticky() bool { + return isLeftBitSet(a, stickyBitPos) +} + +// SetSticky enables the sticky option in ACL. +func (a *basicACLHelper) SetSticky() { + setLeftBit(a, stickyBitPos) +} + +// ResetSticky disables the sticky option in ACL. +func (a *basicACLHelper) ResetSticky() { + resetLeftBit(a, stickyBitPos) +} + +// UserAllowed returns true if user allowed the n-th operation in ACL. +func (a basicACLHelper) UserAllowed(op eacl.Operation) bool { + if n, ok := order[op]; ok { + return isLeftBitSet(a, opOffset+n*bitsPerOp+bitUser) + } + return false +} + +// AllowUser allows user the n-th operation in ACL. +func (a *basicACLHelper) AllowUser(op eacl.Operation) { + if n, ok := order[op]; ok { + setLeftBit(a, opOffset+n*bitsPerOp+bitUser) + } +} + +// ForbidUser forbids user the n-th operation in ACL. +func (a *basicACLHelper) ForbidUser(op eacl.Operation) { + if n, ok := order[op]; ok { + resetLeftBit(a, opOffset+n*bitsPerOp+bitUser) + } +} + +// SystemAllowed returns true if System group allowed the n-th operation is set in ACL. +func (a basicACLHelper) SystemAllowed(op eacl.Operation) bool { + if op != eacl.OperationDelete && op != eacl.OperationRange { + return true + } + + if n, ok := order[op]; ok { + return isLeftBitSet(a, opOffset+n*bitsPerOp+bitSystem) + } + + return false +} + +// AllowSystem allows System group the n-th operation in ACL. +func (a *basicACLHelper) AllowSystem(op eacl.Operation) { + if n, ok := order[op]; ok { + setLeftBit(a, opOffset+n*bitsPerOp+bitSystem) + } +} + +// ForbidSystem forbids System group the n-th operation in ACL. +func (a *basicACLHelper) ForbidSystem(op eacl.Operation) { + if n, ok := order[op]; ok { + resetLeftBit(a, opOffset+n*bitsPerOp+bitSystem) + } +} + +// OthersAllowed returns true if Others group allowed the n-th operation is set in ACL. +func (a basicACLHelper) OthersAllowed(op eacl.Operation) bool { + if n, ok := order[op]; ok { + return isLeftBitSet(a, opOffset+n*bitsPerOp+bitOthers) + } + return false +} + +// AllowOthers allows Others group the n-th operation in ACL. +func (a *basicACLHelper) AllowOthers(op eacl.Operation) { + if n, ok := order[op]; ok { + setLeftBit(a, opOffset+n*bitsPerOp+bitOthers) + } +} + +// ForbidOthers forbids Others group the n-th operation in ACL. +func (a *basicACLHelper) ForbidOthers(op eacl.Operation) { + if n, ok := order[op]; ok { + resetLeftBit(a, opOffset+n*bitsPerOp+bitOthers) + } +} + +// BearerAllowed returns true if Bearer token usage is allowed for n-th operation in ACL. +func (a basicACLHelper) BearerAllowed(op eacl.Operation) bool { + if n, ok := order[op]; ok { + return isLeftBitSet(a, opOffset+n*bitsPerOp+bitBearer) + } + return false +} + +// AllowBearer allows Bearer token usage for n-th operation in ACL. +func (a *basicACLHelper) AllowBearer(op eacl.Operation) { + if n, ok := order[op]; ok { + setLeftBit(a, opOffset+n*bitsPerOp+bitBearer) + } +} + +// ForbidBearer forbids Bearer token usage for n-th operation in ACL. +func (a *basicACLHelper) ForbidBearer(op eacl.Operation) { + if n, ok := order[op]; ok { + resetLeftBit(a, opOffset+n*bitsPerOp+bitBearer) + } +}