forked from TrueCloudLab/frostfs-rest-gw
dc1926f9c6
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
431 lines
12 KiB
Go
431 lines
12 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
|
|
|
sessionv2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
|
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
|
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
|
"github.com/nspcc-dev/neofs-sdk-go/token"
|
|
)
|
|
|
|
// ToNativeAction converts models.Action to appropriate eacl.Action.
|
|
func ToNativeAction(a *models.Action) (eacl.Action, error) {
|
|
if a == nil {
|
|
return eacl.ActionUnknown, fmt.Errorf("unsupported empty action")
|
|
}
|
|
|
|
switch *a {
|
|
case models.ActionALLOW:
|
|
return eacl.ActionAllow, nil
|
|
case models.ActionDENY:
|
|
return eacl.ActionDeny, nil
|
|
default:
|
|
return eacl.ActionUnknown, fmt.Errorf("unsupported action type: '%s'", *a)
|
|
}
|
|
}
|
|
|
|
// FromNativeAction converts eacl.Action to appropriate models.Action.
|
|
func FromNativeAction(a eacl.Action) (*models.Action, error) {
|
|
switch a {
|
|
case eacl.ActionAllow:
|
|
return models.NewAction(models.ActionALLOW), nil
|
|
case eacl.ActionDeny:
|
|
return models.NewAction(models.ActionDENY), nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported action type: '%s'", a)
|
|
}
|
|
}
|
|
|
|
// ToNativeOperation converts models.Operation to appropriate eacl.Operation.
|
|
func ToNativeOperation(o *models.Operation) (eacl.Operation, error) {
|
|
if o == nil {
|
|
return eacl.OperationUnknown, fmt.Errorf("unsupported empty opertaion")
|
|
}
|
|
|
|
switch *o {
|
|
case models.OperationGET:
|
|
return eacl.OperationGet, nil
|
|
case models.OperationHEAD:
|
|
return eacl.OperationHead, nil
|
|
case models.OperationPUT:
|
|
return eacl.OperationPut, nil
|
|
case models.OperationDELETE:
|
|
return eacl.OperationDelete, nil
|
|
case models.OperationSEARCH:
|
|
return eacl.OperationSearch, nil
|
|
case models.OperationRANGE:
|
|
return eacl.OperationRange, nil
|
|
case models.OperationRANGEHASH:
|
|
return eacl.OperationRangeHash, nil
|
|
default:
|
|
return eacl.OperationUnknown, fmt.Errorf("unsupported operation type: '%s'", *o)
|
|
}
|
|
}
|
|
|
|
// FromNativeOperation converts eacl.Operation to appropriate models.Operation.
|
|
func FromNativeOperation(o eacl.Operation) (*models.Operation, error) {
|
|
switch o {
|
|
case eacl.OperationGet:
|
|
return models.NewOperation(models.OperationGET), nil
|
|
case eacl.OperationHead:
|
|
return models.NewOperation(models.OperationHEAD), nil
|
|
case eacl.OperationPut:
|
|
return models.NewOperation(models.OperationPUT), nil
|
|
case eacl.OperationDelete:
|
|
return models.NewOperation(models.OperationDELETE), nil
|
|
case eacl.OperationSearch:
|
|
return models.NewOperation(models.OperationSEARCH), nil
|
|
case eacl.OperationRange:
|
|
return models.NewOperation(models.OperationRANGE), nil
|
|
case eacl.OperationRangeHash:
|
|
return models.NewOperation(models.OperationRANGEHASH), nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported operation type: '%s'", o)
|
|
}
|
|
}
|
|
|
|
// ToNativeHeaderType converts models.HeaderType to appropriate eacl.FilterHeaderType.
|
|
func ToNativeHeaderType(h *models.HeaderType) (eacl.FilterHeaderType, error) {
|
|
if h == nil {
|
|
return eacl.HeaderTypeUnknown, fmt.Errorf("unsupported empty header type")
|
|
}
|
|
|
|
switch *h {
|
|
case models.HeaderTypeOBJECT:
|
|
return eacl.HeaderFromObject, nil
|
|
case models.HeaderTypeREQUEST:
|
|
return eacl.HeaderFromRequest, nil
|
|
case models.HeaderTypeSERVICE:
|
|
return eacl.HeaderFromService, nil
|
|
default:
|
|
return eacl.HeaderTypeUnknown, fmt.Errorf("unsupported header type: '%s'", *h)
|
|
}
|
|
}
|
|
|
|
// FromNativeHeaderType converts eacl.FilterHeaderType to appropriate models.HeaderType.
|
|
func FromNativeHeaderType(h eacl.FilterHeaderType) (*models.HeaderType, error) {
|
|
switch h {
|
|
case eacl.HeaderFromObject:
|
|
return models.NewHeaderType(models.HeaderTypeOBJECT), nil
|
|
case eacl.HeaderFromRequest:
|
|
return models.NewHeaderType(models.HeaderTypeREQUEST), nil
|
|
case eacl.HeaderFromService:
|
|
return models.NewHeaderType(models.HeaderTypeSERVICE), nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported header type: '%s'", h)
|
|
}
|
|
}
|
|
|
|
// ToNativeMatchType converts models.MatchType to appropriate eacl.Match.
|
|
func ToNativeMatchType(t *models.MatchType) (eacl.Match, error) {
|
|
if t == nil {
|
|
return eacl.MatchUnknown, fmt.Errorf("unsupported empty match type")
|
|
}
|
|
|
|
switch *t {
|
|
case models.MatchTypeSTRINGEQUAL:
|
|
return eacl.MatchStringEqual, nil
|
|
case models.MatchTypeSTRINGNOTEQUAL:
|
|
return eacl.MatchStringNotEqual, nil
|
|
default:
|
|
return eacl.MatchUnknown, fmt.Errorf("unsupported match type: '%s'", *t)
|
|
}
|
|
}
|
|
|
|
// FromNativeMatchType converts eacl.Match to appropriate models.MatchType.
|
|
func FromNativeMatchType(t eacl.Match) (*models.MatchType, error) {
|
|
switch t {
|
|
case eacl.MatchStringEqual:
|
|
return models.NewMatchType(models.MatchTypeSTRINGEQUAL), nil
|
|
case eacl.MatchStringNotEqual:
|
|
return models.NewMatchType(models.MatchTypeSTRINGNOTEQUAL), nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported match type: '%s'", t)
|
|
}
|
|
}
|
|
|
|
// ToNativeRole converts models.Role to appropriate eacl.Role.
|
|
func ToNativeRole(r *models.Role) (eacl.Role, error) {
|
|
if r == nil {
|
|
return eacl.RoleUnknown, fmt.Errorf("unsupported empty role")
|
|
}
|
|
|
|
switch *r {
|
|
case models.RoleUSER:
|
|
return eacl.RoleUser, nil
|
|
case models.RoleSYSTEM:
|
|
return eacl.RoleSystem, nil
|
|
case models.RoleOTHERS:
|
|
return eacl.RoleOthers, nil
|
|
default:
|
|
return eacl.RoleUnknown, fmt.Errorf("unsupported role type: '%s'", *r)
|
|
}
|
|
}
|
|
|
|
// FromNativeRole converts eacl.Role to appropriate models.Role.
|
|
func FromNativeRole(r eacl.Role) (*models.Role, error) {
|
|
switch r {
|
|
case eacl.RoleUser:
|
|
return models.NewRole(models.RoleUSER), nil
|
|
case eacl.RoleSystem:
|
|
return models.NewRole(models.RoleSYSTEM), nil
|
|
case eacl.RoleOthers:
|
|
return models.NewRole(models.RoleOTHERS), nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported role type: '%s'", r)
|
|
}
|
|
}
|
|
|
|
// ToNativeVerb converts models.Verb to appropriate session.ContainerSessionVerb.
|
|
func ToNativeVerb(r *models.Verb) (sessionv2.ContainerSessionVerb, error) {
|
|
if r == nil {
|
|
return sessionv2.ContainerVerbUnknown, fmt.Errorf("unsupported empty verb type")
|
|
}
|
|
|
|
switch *r {
|
|
case models.VerbPUT:
|
|
return sessionv2.ContainerVerbPut, nil
|
|
case models.VerbDELETE:
|
|
return sessionv2.ContainerVerbDelete, nil
|
|
case models.VerbSETEACL:
|
|
return sessionv2.ContainerVerbSetEACL, nil
|
|
default:
|
|
return sessionv2.ContainerVerbUnknown, fmt.Errorf("unsupported verb type: '%s'", *r)
|
|
}
|
|
}
|
|
|
|
// ToNativeRule converts models.Rule to appropriate session.ContainerContext.
|
|
func ToNativeRule(r *models.Rule) (*session.ContainerContext, error) {
|
|
var ctx session.ContainerContext
|
|
|
|
verb, err := ToNativeVerb(r.Verb)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ctx.ToV2().SetVerb(verb)
|
|
|
|
if r.ContainerID == "" {
|
|
ctx.ApplyTo(nil)
|
|
} else {
|
|
var cnrID cid.ID
|
|
if err = cnrID.Parse(r.ContainerID); err != nil {
|
|
return nil, fmt.Errorf("couldn't parse container id: %w", err)
|
|
}
|
|
ctx.ApplyTo(&cnrID)
|
|
}
|
|
|
|
return &ctx, nil
|
|
}
|
|
|
|
// ToNativeContainerToken converts models.Bearer to appropriate session.Token.
|
|
func ToNativeContainerToken(b *models.Bearer) (*session.Token, error) {
|
|
sctx, err := ToNativeRule(b.Container)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("couldn't transform rule to native: %w", err)
|
|
}
|
|
tok := session.NewToken()
|
|
tok.SetContext(sctx)
|
|
|
|
return tok, nil
|
|
}
|
|
|
|
// ToNativeRecord converts models.Record to appropriate eacl.Record.
|
|
func ToNativeRecord(r *models.Record) (*eacl.Record, error) {
|
|
var record eacl.Record
|
|
|
|
action, err := ToNativeAction(r.Action)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
record.SetAction(action)
|
|
|
|
operation, err := ToNativeOperation(r.Operation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
record.SetOperation(operation)
|
|
|
|
for _, filter := range r.Filters {
|
|
headerType, err := ToNativeHeaderType(filter.HeaderType)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
matchType, err := ToNativeMatchType(filter.MatchType)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if filter.Key == nil || filter.Value == nil {
|
|
return nil, fmt.Errorf("invalid filter")
|
|
}
|
|
record.AddFilter(headerType, matchType, *filter.Key, *filter.Value)
|
|
}
|
|
|
|
targets := make([]eacl.Target, len(r.Targets))
|
|
for i, target := range r.Targets {
|
|
trgt, err := ToNativeTarget(target)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
targets[i] = *trgt
|
|
}
|
|
record.SetTargets(targets...)
|
|
|
|
return &record, nil
|
|
}
|
|
|
|
// FromNativeRecord converts eacl.Record to appropriate models.Record.
|
|
func FromNativeRecord(r eacl.Record) (*models.Record, error) {
|
|
var err error
|
|
var record models.Record
|
|
|
|
record.Action, err = FromNativeAction(r.Action())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
record.Operation, err = FromNativeOperation(r.Operation())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
record.Filters = make([]*models.Filter, len(r.Filters()))
|
|
for i, filter := range r.Filters() {
|
|
headerType, err := FromNativeHeaderType(filter.From())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
matchType, err := FromNativeMatchType(filter.Matcher())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
record.Filters[i] = &models.Filter{
|
|
HeaderType: headerType,
|
|
Key: NewString(filter.Key()),
|
|
MatchType: matchType,
|
|
Value: NewString(filter.Value()),
|
|
}
|
|
}
|
|
|
|
record.Targets = make([]*models.Target, len(r.Targets()))
|
|
for i, target := range r.Targets() {
|
|
trgt, err := FromNativeTarget(target)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
record.Targets[i] = trgt
|
|
}
|
|
|
|
return &record, nil
|
|
}
|
|
|
|
// ToNativeTarget converts models.Target to appropriate eacl.Target.
|
|
func ToNativeTarget(t *models.Target) (*eacl.Target, error) {
|
|
var target eacl.Target
|
|
|
|
role, err := ToNativeRole(t.Role)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
target.SetRole(role)
|
|
|
|
keys := make([][]byte, len(t.Keys))
|
|
for i, key := range t.Keys {
|
|
binaryKey, err := hex.DecodeString(key)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("couldn't decode target key: %w", err)
|
|
}
|
|
keys[i] = binaryKey
|
|
}
|
|
target.SetBinaryKeys(keys)
|
|
|
|
return &target, nil
|
|
}
|
|
|
|
// FromNativeTarget converts eacl.Target to appropriate models.Target.
|
|
func FromNativeTarget(t eacl.Target) (*models.Target, error) {
|
|
var err error
|
|
var target models.Target
|
|
|
|
target.Role, err = FromNativeRole(t.Role())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
target.Keys = make([]string, len(t.BinaryKeys()))
|
|
for i, key := range t.BinaryKeys() {
|
|
target.Keys[i] = hex.EncodeToString(key)
|
|
}
|
|
|
|
return &target, nil
|
|
}
|
|
|
|
// ToNativeObjectToken converts Bearer to appropriate token.BearerToken.
|
|
func ToNativeObjectToken(b *models.Bearer) (*token.BearerToken, error) {
|
|
table, err := ToNativeTable(b.Object)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var btoken token.BearerToken
|
|
btoken.SetEACLTable(table)
|
|
|
|
return &btoken, nil
|
|
}
|
|
|
|
// ToNativeTable converts records to eacl.Table.
|
|
func ToNativeTable(records []*models.Record) (*eacl.Table, error) {
|
|
table := eacl.NewTable()
|
|
|
|
for _, rec := range records {
|
|
record, err := ToNativeRecord(rec)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("couldn't transform record to native: %w", err)
|
|
}
|
|
table.AddRecord(record)
|
|
}
|
|
|
|
return table, nil
|
|
}
|
|
|
|
// ToNativeMatchFilter converts models.SearchMatch to object.SearchMatchType.
|
|
func ToNativeMatchFilter(s *models.SearchMatch) (object.SearchMatchType, error) {
|
|
if s == nil {
|
|
return object.MatchUnknown, fmt.Errorf("unsupported empty verb type")
|
|
}
|
|
|
|
switch *s {
|
|
case models.SearchMatchMatchStringEqual:
|
|
return object.MatchStringEqual, nil
|
|
case models.SearchMatchMatchStringNotEqual:
|
|
return object.MatchStringNotEqual, nil
|
|
case models.SearchMatchMatchNotPresent:
|
|
return object.MatchNotPresent, nil
|
|
case models.SearchMatchMatchCommonPrefix:
|
|
return object.MatchCommonPrefix, nil
|
|
default:
|
|
return object.MatchUnknown, fmt.Errorf("unsupported search match: '%s'", *s)
|
|
}
|
|
}
|
|
|
|
// ToNativeFilters converts models.SearchFilters to object.SearchFilters.
|
|
func ToNativeFilters(fs *models.SearchFilters) (object.SearchFilters, error) {
|
|
filters := object.NewSearchFilters()
|
|
filters.AddRootFilter()
|
|
|
|
for _, f := range fs.Filters {
|
|
matchFilter, err := ToNativeMatchFilter(f.Match)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
filters.AddFilter(*f.Key, *f.Value, matchFilter)
|
|
}
|
|
|
|
return filters, nil
|
|
}
|