2023-10-05 13:25:25 +00:00
|
|
|
package frostfsid
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-02-19 07:51:41 +00:00
|
|
|
"encoding/hex"
|
2023-10-05 13:25:25 +00:00
|
|
|
"fmt"
|
2023-12-13 14:44:18 +00:00
|
|
|
"strconv"
|
2023-10-05 13:25:25 +00:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
2023-12-13 14:44:18 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
2023-12-08 07:44:13 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
|
2023-11-16 11:39:58 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
2023-12-08 07:44:13 +00:00
|
|
|
frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
|
2023-10-05 13:25:25 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
2023-12-13 14:44:18 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2023-10-05 13:25:25 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
|
|
)
|
|
|
|
|
|
|
|
type FrostFSID struct {
|
|
|
|
cli *client.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
type Config struct {
|
|
|
|
// RPCAddress is an endpoint to connect to neo rpc.
|
|
|
|
RPCAddress string
|
|
|
|
|
|
|
|
// Contract is hash of contract or its name in NNS.
|
|
|
|
Contract string
|
|
|
|
|
2023-12-21 14:34:46 +00:00
|
|
|
// ProxyContract is hash of proxy contract or its name in NNS to interact with frostfsid.
|
|
|
|
ProxyContract string
|
|
|
|
|
2023-10-05 13:25:25 +00:00
|
|
|
// Key is used to interact with frostfsid contract.
|
|
|
|
// If this is nil than random key will be generated.
|
|
|
|
Key *keys.PrivateKey
|
|
|
|
}
|
|
|
|
|
2023-11-16 11:39:58 +00:00
|
|
|
var (
|
2023-12-13 14:44:18 +00:00
|
|
|
_ api.FrostFSID = (*FrostFSID)(nil)
|
|
|
|
_ authmate.FrostFSID = (*FrostFSID)(nil)
|
|
|
|
_ handler.FrostFSID = (*FrostFSID)(nil)
|
2023-11-16 11:39:58 +00:00
|
|
|
)
|
2023-10-05 13:25:25 +00:00
|
|
|
|
|
|
|
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
|
|
|
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
2023-12-08 07:44:13 +00:00
|
|
|
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
2023-10-05 13:25:25 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
key := cfg.Key
|
|
|
|
if key == nil {
|
|
|
|
if key, err = keys.NewPrivateKey(); err != nil {
|
|
|
|
return nil, fmt.Errorf("generate anon private key for frostfsid: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rpcCli, err := rpcclient.New(ctx, cfg.RPCAddress, rpcclient.Options{})
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("init rpc client: %w", err)
|
|
|
|
}
|
|
|
|
|
2023-12-21 14:34:46 +00:00
|
|
|
var opt client.Options
|
|
|
|
opt.ProxyContract, err = frostfsutil.ResolveContractHash(cfg.ProxyContract, cfg.RPCAddress)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
cli, err := client.New(rpcCli, wallet.NewAccountFromPrivateKey(key), contractHash, opt)
|
2023-10-05 13:25:25 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("init frostfsid client: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &FrostFSID{
|
|
|
|
cli: cli,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FrostFSID) ValidatePublicKey(key *keys.PublicKey) error {
|
|
|
|
_, err := f.cli.GetSubjectByKey(key)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-12-21 14:34:46 +00:00
|
|
|
func (f *FrostFSID) RegisterPublicKey(ns string, key *keys.PublicKey) error {
|
|
|
|
_, err := f.cli.Wait(f.cli.CreateSubject(ns, key))
|
2023-11-16 11:39:58 +00:00
|
|
|
if err != nil && !strings.Contains(err.Error(), "subject already exists") {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2023-12-08 07:44:13 +00:00
|
|
|
|
|
|
|
func (f *FrostFSID) GetUserAddress(namespace, name string) (string, error) {
|
|
|
|
key, err := f.cli.GetSubjectKeyByName(namespace, name)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return key.Address(), nil
|
|
|
|
}
|
2023-12-13 14:44:18 +00:00
|
|
|
|
2024-02-19 07:51:41 +00:00
|
|
|
func (f *FrostFSID) GetUserKey(account, name string) (string, error) {
|
|
|
|
key, err := f.cli.GetSubjectKeyByName(account, name)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return hex.EncodeToString(key.Bytes()), nil
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:44:18 +00:00
|
|
|
func (f *FrostFSID) GetUserGroupIDs(userHash util.Uint160) ([]string, error) {
|
|
|
|
subjExt, err := f.cli.GetSubjectExtended(userHash)
|
|
|
|
if err != nil {
|
|
|
|
if strings.Contains(err.Error(), "not found") {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
res := make([]string, len(subjExt.Groups))
|
|
|
|
for i, group := range subjExt.Groups {
|
|
|
|
res[i] = strconv.FormatInt(group.ID, 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
return res, nil
|
|
|
|
}
|