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) GetUserGroupIDsAndClaims(userHash util.Uint160) ([]string, map[string]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, nil } return nil, nil, err } res := make([]string, len(subj.Groups)) for i, group := range subj.Groups { res[i] = strconv.FormatInt(group.ID, 10) } return res, subj.KV, 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 }