forked from TrueCloudLab/frostfs-rest-gw
246 lines
6.4 KiB
Go
246 lines
6.4 KiB
Go
|
package handlers
|
||
|
|
||
|
import (
|
||
|
"encoding/hex"
|
||
|
"fmt"
|
||
|
|
||
|
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)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
// ToNativeObjectToken converts Bearer to appropriate token.BearerToken.
|
||
|
func ToNativeObjectToken(b *models.Bearer) (*token.BearerToken, error) {
|
||
|
var btoken token.BearerToken
|
||
|
var table eacl.Table
|
||
|
|
||
|
for _, rec := range b.Object {
|
||
|
record, err := ToNativeRecord(rec)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("couldn't transform record to native: %w", err)
|
||
|
}
|
||
|
table.AddRecord(record)
|
||
|
}
|
||
|
|
||
|
btoken.SetEACLTable(&table)
|
||
|
|
||
|
return &btoken, nil
|
||
|
}
|