generated from TrueCloudLab/basic
203 lines
5.7 KiB
Go
203 lines
5.7 KiB
Go
package chains
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
|
|
ffsidclient "git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
|
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
|
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
|
"git.frostfs.info/dkirillov/policy-reader/internal/resolver"
|
|
neoflags "github.com/nspcc-dev/neo-go/cli/flags"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
var listUserCmd = &cobra.Command{
|
|
Use: "list-user",
|
|
Short: "List user related policies",
|
|
Long: "List user related policies along with filtering by service (s3/storage)",
|
|
Example: `policy-reader user -r http://localhost:40332 list --user NiGqBpUdMvAC68SxUeyYwVPyBCsqzNuof
|
|
policy-reader user -r http://localhost:40332 --policy-hash 81c1a41d09e08087a4b679418b12be5d3ab15742 list --user NiGqBpUdMvAC68SxUeyYwVPyBCsqzNuofL --service s3`,
|
|
RunE: runListCmd,
|
|
}
|
|
|
|
var errUnknownServiceType = errors.New("unknown service type")
|
|
|
|
const (
|
|
userFlag = "user"
|
|
namespaceFlag = "namespace"
|
|
serviceFlag = "service"
|
|
decodeIDFlag = "decode-id"
|
|
)
|
|
|
|
func initListUserCmd() {
|
|
listUserCmd.Flags().String(userFlag, "", "User address or name in frostfsid contract (if name is provided than 'namespace' should be set too)")
|
|
listUserCmd.Flags().String(namespaceFlag, "", "Namespace where user name will be looked up")
|
|
listUserCmd.Flags().String(serviceFlag, "none", "Service (none/s3/storage) to filter chains")
|
|
listUserCmd.Flags().Bool(decodeIDFlag, false, "Use this flag to additionally decode chain id")
|
|
|
|
_ = listUserCmd.MarkFlagRequired(userFlag)
|
|
}
|
|
|
|
func runListCmd(cmd *cobra.Command, _ []string) error {
|
|
service, err := parseService(viper.GetString(serviceFlag))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
endpoint := viper.GetString(rpcEndpointFlag)
|
|
|
|
policyHash, err := resolver.ResolveContractHash(endpoint, viper.GetString(policyHashFlag))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
frostfsidHash, err := resolver.ResolveContractHash(endpoint, viper.GetString(frostfsidHashFlag))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
rpcCli, err := rpcclient.New(cmd.Context(), endpoint, rpcclient.Options{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
acc, err := wallet.NewAccount()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ffsidCli, err := ffsidclient.New(rpcCli, acc, frostfsidHash, ffsidclient.Options{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
subj, err := resolveSubject(ffsidCli, viper.GetString(namespaceFlag), viper.GetString(userFlag))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
printSubject(cmd, subj)
|
|
|
|
res, err := commonclient.ReadIteratorItems(invoker.New(rpcCli, nil), 100, policyHash, "iteratorChainsByPrefix", big.NewInt(int64(policycontract.Namespace)), subj.Namespace, string(service))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
decodeID := viper.GetBool(decodeIDFlag)
|
|
|
|
cmd.Printf("user namespace '%s' policies: %d\n", subj.Namespace, len(res))
|
|
if err = printChains(cmd, res, decodeID); err != nil {
|
|
return err
|
|
}
|
|
|
|
userEntity := big.NewInt(int64(policycontract.User))
|
|
userEntityName := fmt.Sprintf("%s:%s", subj.Namespace, subj.PrimaryKey.Address())
|
|
|
|
res, err = commonclient.ReadIteratorItems(invoker.New(rpcCli, nil), 100, policyHash, "iteratorChainsByPrefix", userEntity, userEntityName, string(service))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd.Printf("user policies: %d\n", len(res))
|
|
if err = printChains(cmd, res, decodeID); err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd.Printf("user group policies: %d\n", len(subj.Groups))
|
|
|
|
groupEntity := big.NewInt(int64(policycontract.Group))
|
|
for _, group := range subj.Groups {
|
|
groupEntityName := fmt.Sprintf("%s:%d", group.Namespace, group.ID)
|
|
|
|
res, err = commonclient.ReadIteratorItems(invoker.New(rpcCli, nil), 100, policyHash, "iteratorChainsByPrefix", groupEntity, groupEntityName, string(service))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd.Printf("user group '%s' (id: %d) policies: %d\n", group.Name, group.ID, len(res))
|
|
if err = printChains(cmd, res, decodeID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func printChains(cmd *cobra.Command, list []stackitem.Item, decodeID bool) error {
|
|
for _, item := range list {
|
|
bytes, err := item.TryBytes()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var chain apechain.Chain
|
|
if err = chain.DecodeBytes(bytes); err != nil {
|
|
cmd.Printf("invalid chain format: %s\n", base64.StdEncoding.EncodeToString(bytes))
|
|
continue
|
|
}
|
|
|
|
raw, err := chain.MarshalJSON()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if decodeID {
|
|
cmd.Println(string(chain.ID), string(raw))
|
|
} else {
|
|
cmd.Println(string(raw))
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func resolveSubject(ffsid *ffsidclient.Client, namespace, userName string) (*ffsidclient.SubjectExtended, error) {
|
|
if userHash, err := neoflags.ParseAddress(userName); err == nil {
|
|
subj, err := ffsid.GetSubject(userHash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return ffsid.GetSubjectExtended(subj.PrimaryKey.GetScriptHash())
|
|
}
|
|
|
|
subj, err := ffsid.GetSubjectByName(namespace, userName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return ffsid.GetSubjectExtended(subj.PrimaryKey.GetScriptHash())
|
|
}
|
|
|
|
func parseService(service string) (apechain.Name, error) {
|
|
switch service {
|
|
case "none":
|
|
return "", nil
|
|
case "s3":
|
|
return apechain.S3, nil
|
|
case "storage":
|
|
return apechain.Ingress, nil
|
|
}
|
|
|
|
return "", errUnknownServiceType
|
|
}
|
|
|
|
func printSubject(cmd *cobra.Command, subj *ffsidclient.SubjectExtended) {
|
|
cmd.Println("ns:", subj.Namespace)
|
|
cmd.Println("name:", subj.Name)
|
|
cmd.Println("key:", hex.EncodeToString(subj.PrimaryKey.Bytes()))
|
|
cmd.Println("claims:")
|
|
for k, v := range subj.KV {
|
|
cmd.Println(k, v)
|
|
}
|
|
}
|