package policy import ( "fmt" policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain" "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine" "github.com/google/uuid" "github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/util" "go.uber.org/zap" ) type MorphRuleChainStorage struct { contract Contract cache *cache.MorphPolicyCache log *zap.Logger } type MorphRuleChainStorageConfig struct { Contract Contract Cache *cache.MorphPolicyCache Log *zap.Logger } var _ engine.MorphRuleChainStorageReader = (*MorphRuleChainStorage)(nil) const bucketPolicyPrefix = 'b' func NewMorphRuleChainStorage(config *MorphRuleChainStorageConfig) *MorphRuleChainStorage { return &MorphRuleChainStorage{ contract: config.Contract, cache: config.Cache, log: config.Log, } } func (c *MorphRuleChainStorage) GetAdmin() (util.Uint160, error) { panic("should never be called") } func (c *MorphRuleChainStorage) ListTargetsIterator(engine.TargetType) (uuid.UUID, result.Iterator, error) { panic("should never be called") } func (c *MorphRuleChainStorage) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) { key := cache.MorphPolicyCacheKey{Target: target, Name: name} list := c.cache.Get(key) if list != nil { return list, nil } listChains, err := c.contract.ListChains(getKind(target), target.Name, []byte(name)) if err != nil { return nil, err } list = make([]*chain.Chain, len(listChains)) for i, listChain := range listChains { var item chain.Chain if err = item.DecodeBytes(listChain); err != nil { return nil, fmt.Errorf("unmarshal chain: %w", err) } list[i] = &item } if err = c.cache.Put(key, list); err != nil { c.log.Warn(logs.CouldntCacheListPolicyChains) } return list, nil } func (c *MorphRuleChainStorage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error { c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cnrID.EncodeToString()), Name: chain.S3}) tx := c.contract.StartTx() tx.AddChain(policycontract.IAM, ns, getBucketPolicyName(cnrID), policy) for i := range chains { tx.AddChain(policycontract.Container, cnrID.EncodeToString(), chains[i].ID, chains[i].Bytes()) } return c.contract.SendTx(tx) } func (c *MorphRuleChainStorage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainIDs []chain.ID) error { c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cnrID.EncodeToString()), Name: chain.S3}) tx := c.contract.StartTx() for _, chainID := range chainIDs { tx.RemoveChain(policycontract.Container, cnrID.EncodeToString(), chainID) } tx.RemoveChain(policycontract.IAM, ns, getBucketPolicyName(cnrID)) return c.contract.SendTx(tx) } func (c *MorphRuleChainStorage) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) { return c.contract.GetChain(policycontract.IAM, ns, getBucketPolicyName(cnrID)) } func (c *MorphRuleChainStorage) SaveACLChains(cid string, chains []*chain.Chain) error { c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cid), Name: chain.S3}) c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cid), Name: chain.Ingress}) tx := c.contract.StartTx() for i := range chains { tx.AddChain(policycontract.Container, cid, chains[i].ID, chains[i].Bytes()) } return c.contract.SendTx(tx) } func getKind(target engine.Target) policycontract.Kind { switch target.Type { case engine.Container: return policycontract.Container case engine.User: return 'u' case engine.Group: return 'g' default: return policycontract.Namespace } } func getBucketPolicyName(cnrID cid.ID) []byte { return append([]byte{bucketPolicyPrefix}, cnrID[:]...) }