package ape import ( "context" "fmt" "strconv" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" aperesource "git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource" nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native" ) type request struct { operation string resource *resource properties map[string]string } var _ aperesource.Request = (*request)(nil) type resource struct { name string properties map[string]string } var _ aperesource.Resource = (*resource)(nil) func (r *resource) Name() string { return r.name } func (r *resource) Property(key string) string { return r.properties[key] } func (r *request) Operation() string { return r.operation } func (r *request) Property(key string) string { return r.properties[key] } func (r *request) Resource() aperesource.Resource { return r.resource } func nativeSchemaRole(role acl.Role) string { switch role { case acl.RoleOwner: return nativeschema.PropertyValueContainerRoleOwner case acl.RoleContainer: return nativeschema.PropertyValueContainerRoleContainer case acl.RoleInnerRing: return nativeschema.PropertyValueContainerRoleIR case acl.RoleOthers: return nativeschema.PropertyValueContainerRoleOthers default: return "" } } func resourceName(cid cid.ID, oid *oid.ID, namespace string) string { if namespace == "root" || namespace == "" { if oid != nil { return fmt.Sprintf(nativeschema.ResourceFormatRootContainerObject, cid.EncodeToString(), oid.EncodeToString()) } return fmt.Sprintf(nativeschema.ResourceFormatRootContainerObjects, cid.EncodeToString()) } if oid != nil { return fmt.Sprintf(nativeschema.ResourceFormatNamespaceContainerObject, namespace, cid.EncodeToString(), oid.EncodeToString()) } return fmt.Sprintf(nativeschema.ResourceFormatNamespaceContainerObjects, namespace, cid.EncodeToString()) } // objectProperties collects object properties from address parameters and a header if it is passed. func objectProperties(cnr cid.ID, oid *oid.ID, cnrOwner user.ID, header *objectV2.Header) map[string]string { objectProps := map[string]string{ nativeschema.PropertyKeyObjectContainerID: cnr.EncodeToString(), } objectProps[nativeschema.PropertyKeyContainerOwnerID] = cnrOwner.EncodeToString() if oid != nil { objectProps[nativeschema.PropertyKeyObjectID] = oid.String() } if header == nil { return objectProps } objV2 := new(objectV2.Object) objV2.SetHeader(header) objSDK := objectSDK.NewFromV2(objV2) objectProps[nativeschema.PropertyKeyObjectVersion] = objSDK.Version().String() objectProps[nativeschema.PropertyKeyObjectOwnerID] = objSDK.OwnerID().EncodeToString() objectProps[nativeschema.PropertyKeyObjectCreationEpoch] = strconv.Itoa(int(objSDK.CreationEpoch())) objectProps[nativeschema.PropertyKeyObjectPayloadLength] = strconv.Itoa(int(objSDK.PayloadSize())) objectProps[nativeschema.PropertyKeyObjectType] = objSDK.Type().String() pcs, isSet := objSDK.PayloadChecksum() if isSet { objectProps[nativeschema.PropertyKeyObjectPayloadHash] = pcs.String() } hcs, isSet := objSDK.PayloadHomomorphicHash() if isSet { objectProps[nativeschema.PropertyKeyObjectHomomorphicHash] = hcs.String() } for _, attr := range header.GetAttributes() { objectProps[attr.GetKey()] = attr.GetValue() } return objectProps } // newAPERequest creates an APE request to be passed to a chain router. It collects resource properties from // header provided by headerProvider. If it cannot be found in headerProvider, then properties are // initialized from header given in prm (if it is set). Otherwise, just CID and OID are set to properties. func (c *checkerImpl) newAPERequest(ctx context.Context, prm Prm) (*request, error) { switch prm.Method { case nativeschema.MethodGetObject, nativeschema.MethodHeadObject, nativeschema.MethodRangeObject, nativeschema.MethodHashObject, nativeschema.MethodDeleteObject: if prm.Object == nil { return nil, fmt.Errorf("method %s: %w", prm.Method, errMissingOID) } case nativeschema.MethodSearchObject, nativeschema.MethodPutObject: default: return nil, fmt.Errorf("unknown method: %s", prm.Method) } var header *objectV2.Header if prm.Header != nil { header = prm.Header } else if prm.Object != nil && !prm.WithoutHeaderRequest { headerObjSDK, err := c.headerProvider.GetHeader(ctx, prm.Container, *prm.Object) if err == nil { header = headerObjSDK.ToV2().GetHeader() } } return &request{ operation: prm.Method, resource: &resource{ name: resourceName(prm.Container, prm.Object, prm.Namespace), properties: objectProperties(prm.Container, prm.Object, prm.ContainerOwner, header), }, properties: map[string]string{ nativeschema.PropertyKeyActorPublicKey: prm.SenderKey, nativeschema.PropertyKeyActorRole: prm.Role, }, }, nil }