frostfs-s3-gw/internal/frostfs/frostfsid/frostfsid.go
Denis Kirillov 5315f7b733 [#269] Create frostfsid wrapper with cache
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2024-04-18 09:32:30 +03:00

128 lines
3 KiB
Go

package frostfsid
import (
"encoding/hex"
"errors"
"strconv"
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util"
"go.uber.org/zap"
)
type FrostFSID struct {
frostfsid *contract.FrostFSID
cache *cache.FrostfsIDCache
log *zap.Logger
}
type Config struct {
Cache *cache.FrostfsIDCache
FrostFSID *contract.FrostFSID
Logger *zap.Logger
}
var (
_ api.FrostFSID = (*FrostFSID)(nil)
_ handler.FrostFSID = (*FrostFSID)(nil)
)
// NewFrostFSID creates new FrostfsID wrapper.
func NewFrostFSID(cfg Config) (*FrostFSID, error) {
switch {
case cfg.FrostFSID == nil:
return nil, errors.New("missing frostfsid client")
case cfg.Cache == nil:
return nil, errors.New("missing frostfsid cache")
case cfg.Logger == nil:
return nil, errors.New("missing frostfsid logger")
}
return &FrostFSID{
frostfsid: cfg.FrostFSID,
cache: cfg.Cache,
log: cfg.Logger,
}, nil
}
func (f *FrostFSID) ValidatePublicKey(key *keys.PublicKey) error {
_, err := f.getSubject(key.GetScriptHash())
return err
}
func (f *FrostFSID) GetUserGroupIDs(userHash util.Uint160) ([]string, error) {
subj, err := f.getSubject(userHash)
if err != nil {
if strings.Contains(err.Error(), "not found") {
f.log.Debug(logs.UserGroupsListIsEmpty, zap.Error(err))
return nil, nil
}
return nil, err
}
res := make([]string, len(subj.Groups))
for i, group := range subj.Groups {
res[i] = strconv.FormatInt(group.ID, 10)
}
return res, nil
}
func (f *FrostFSID) getSubject(addr util.Uint160) (*client.SubjectExtended, error) {
if subj := f.cache.GetSubject(addr); subj != nil {
return subj, nil
}
subj, err := f.frostfsid.GetSubjectExtended(addr)
if err != nil {
return nil, err
}
if err = f.cache.PutSubject(addr, subj); err != nil {
f.log.Warn(logs.CouldntCacheSubject, zap.Error(err))
}
return subj, nil
}
func (f *FrostFSID) GetUserAddress(namespace, name string) (string, error) {
userKey, err := f.getUserKey(namespace, name)
if err != nil {
return "", err
}
return userKey.Address(), nil
}
func (f *FrostFSID) GetUserKey(namespace, name string) (string, error) {
userKey, err := f.getUserKey(namespace, name)
if err != nil {
return "", err
}
return hex.EncodeToString(userKey.Bytes()), nil
}
func (f *FrostFSID) getUserKey(namespace, name string) (*keys.PublicKey, error) {
if userKey := f.cache.GetUserKey(namespace, name); userKey != nil {
return userKey, nil
}
userKey, err := f.frostfsid.GetSubjectKeyByName(namespace, name)
if err != nil {
return nil, err
}
if err = f.cache.PutUserKey(namespace, name, userKey); err != nil {
f.log.Warn(logs.CouldntCacheUserKey, zap.Error(err))
}
return userKey, nil
}