forked from TrueCloudLab/frostfs-s3-gw
[#104] Support NEP-6 for authmate
Drop neofs-crypto. Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
39a43c21a1
commit
52c63d4c44
11 changed files with 227 additions and 172 deletions
27
README.md
27
README.md
|
@ -109,7 +109,7 @@ default. To enable them use `--pprof` and `--metrics` flags or
|
|||
|
||||
## NeoFS AuthMate
|
||||
|
||||
Authmate is a tool to create gateway key pairs and AWS credentials. AWS users
|
||||
Authmate is a tool to create gateway AWS credentials. AWS users
|
||||
are authenticated with access key IDs and secrets, while NeoFS users are
|
||||
authenticated with key pairs. To complicate things further we have S3 gateway
|
||||
that usually acts on behalf of some user, but user doesn't necessarily want to
|
||||
|
@ -119,7 +119,7 @@ To solve this we use NeoFS bearer tokens that are signed by the owner (NeoFS
|
|||
"user") and that can implement any kind of policy for NeoFS requests allowed
|
||||
using this token. But tokens can't be used directly as AWS credentials, thus
|
||||
they're stored on NeoFS as regular objects and access key ID is just an
|
||||
address of this object while secret is an SHA256 hash of this key.
|
||||
address of this object while secret is generated randomly.
|
||||
|
||||
Tokens are not stored on NeoFS in plaintext, they're encrypted with a set of
|
||||
gateway keys. So in order for gateway to be able to successfully extract bearer
|
||||
|
@ -127,6 +127,17 @@ token the object needs to be stored in a container available for the gateway
|
|||
to read and it needs to be encrypted with this gateway's key (among others
|
||||
potentially).
|
||||
|
||||
### Variables
|
||||
Authmate support the following variables to decrypt wallets provided by `--wallet` and `--gate-wallet`
|
||||
parameters respectevely:
|
||||
* `AUTHMATE_WALLET_PASSPHRASE`
|
||||
* `AUTHMATE_WALLET_GATE_PASSPHRASE`
|
||||
|
||||
If the passphrase is not specified, you will be asked to enter the password interactively:
|
||||
```
|
||||
Enter password for wallet.json >
|
||||
```
|
||||
|
||||
#### Generation of wallet
|
||||
|
||||
To generate wallets for gateways, run the following command:
|
||||
|
@ -234,7 +245,7 @@ token will not be created.
|
|||
|
||||
Example of a command to issue a secret with custom rules for multiple gates:
|
||||
```
|
||||
$ ./neofs-authmate issue-secret --neofs-key user.key \
|
||||
$ ./neofs-authmate issue-secret --wallet wallet.json \
|
||||
--peer 192.168.130.71:8080 \
|
||||
--bearer-rules '{"records":[{"operation":"PUT","action":"ALLOW","filters":[],"targets":[{"role":"OTHERS","keys":[]}]}]}' \
|
||||
--gate-public-key dd34f6dce9a4ce0990869ec6bd33a40e102a5798881cfe61d03a5659ceee1a64 \
|
||||
|
@ -242,6 +253,7 @@ $ ./neofs-authmate issue-secret --neofs-key user.key \
|
|||
--create-session-token \
|
||||
--session-rules '{"verb":"DELETE","wildcard":false,"containerID":{"value":"%CID"}}'
|
||||
|
||||
Enter password for wallet.json >
|
||||
{
|
||||
"access_key_id": "5g933dyLEkXbbAspouhPPTiyLZRg4axBW1axSPD87eVT_AiXsH4AjYy1iTJ4C1WExzjBrSobJsQFWEyKLREe5sQYM",
|
||||
"secret_access_key": "438bbd8243060e1e1c9dd4821756914a6e872ce29bf203b68f81b140ac91231c",
|
||||
|
@ -255,14 +267,17 @@ any S3 client.
|
|||
#### Obtainment of a secret access key
|
||||
|
||||
You can get a secret access key associated with access key ID by obtaining a
|
||||
secret stored on the NeoFS network:
|
||||
secret stored on the NeoFS network. Here example of providing one password (for `wallet.json`) via env variable
|
||||
and other (for `gate-wallet.json`) interactively:
|
||||
|
||||
```
|
||||
$ ./neofs-authmate obtain-secret --neofs-key user.key \
|
||||
$ AUTHMATE_WALLET_PASSPHRASE=some-pwd \
|
||||
./neofs-authmate obtain-secret --wallet wallet.json \
|
||||
--peer 192.168.130.71:8080 \
|
||||
--gate-private-key b8ba980eb70b959be99915d2e0ad377809984ccd1dac0a6551907f81c2b33d21 \
|
||||
--gate-wallet gate-wallet.json \
|
||||
--access-key-id 5g933dyLEkXbbAspouhPPTiyLZRg4axBW1axSPD87eVT_AiXsH4AjYy1iTJ4C1WExzjBrSobJsQFWEyKLREe5sQYM
|
||||
|
||||
Enter password for gate-wallet.json >
|
||||
{
|
||||
"secret_access_key": "438bbd8243060e1e1c9dd4821756914a6e872ce29bf203b68f81b140ac91231c"
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package auth
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -13,6 +12,7 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/creds/tokens"
|
||||
|
@ -56,7 +56,7 @@ func (p prs) Seek(_ int64, _ int) (int64, error) {
|
|||
var _ io.ReadSeeker = prs(0)
|
||||
|
||||
// New creates an instance of AuthCenter.
|
||||
func New(conns pool.Pool, key *ecdsa.PrivateKey) Center {
|
||||
func New(conns pool.Pool, key *keys.PrivateKey) Center {
|
||||
return ¢er{
|
||||
cli: tokens.New(conns, key),
|
||||
reg: ®expSubmatcher{re: authorizationFieldRegexp},
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/container"
|
||||
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
|
||||
|
@ -20,7 +21,6 @@ import (
|
|||
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/session"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/token"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/policy"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/creds/tokens"
|
||||
|
@ -48,8 +48,8 @@ type (
|
|||
IssueSecretOptions struct {
|
||||
ContainerID *cid.ID
|
||||
ContainerFriendlyName string
|
||||
NeoFSKey *ecdsa.PrivateKey
|
||||
GatesPublicKeys []*ecdsa.PublicKey
|
||||
NeoFSKey *keys.PrivateKey
|
||||
GatesPublicKeys []*keys.PublicKey
|
||||
EACLRules []byte
|
||||
ContextRules []byte
|
||||
SessionTkn bool
|
||||
|
@ -58,7 +58,7 @@ type (
|
|||
// ObtainSecretOptions contains options for passing to Agent.ObtainSecret method.
|
||||
ObtainSecretOptions struct {
|
||||
SecretAddress string
|
||||
GatePrivateKey *ecdsa.PrivateKey
|
||||
GatePrivateKey *keys.PrivateKey
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -127,7 +127,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
|
|||
return err
|
||||
}
|
||||
|
||||
oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey)
|
||||
oid, err := ownerIDFromNeoFSKey(options.NeoFSKey.PublicKey())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
|
|||
ir := &issuingResult{
|
||||
AccessKeyID: accessKeyID,
|
||||
SecretAccessKey: secrets.AccessKey,
|
||||
OwnerPrivateKey: hex.EncodeToString(crypto.MarshalPrivateKey(secrets.EphemeralKey)),
|
||||
OwnerPrivateKey: hex.EncodeToString(secrets.EphemeralKey.Bytes()),
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
|
@ -257,7 +257,7 @@ func buildContext(rules []byte) (*session.ContainerContext, error) {
|
|||
return sessionCtx, nil
|
||||
}
|
||||
|
||||
func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, gateKey *ecdsa.PublicKey) (*token.BearerToken, error) {
|
||||
func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, gateKey *keys.PublicKey) (*token.BearerToken, error) {
|
||||
oid, err := ownerIDFromNeoFSKey(gateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -268,10 +268,10 @@ func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, gateKey *ecdsa.P
|
|||
bearerToken.SetOwner(oid)
|
||||
bearerToken.SetLifetime(math.MaxUint64, 0, 0)
|
||||
|
||||
return bearerToken, bearerToken.SignToken(key)
|
||||
return bearerToken, bearerToken.SignToken(&key.PrivateKey)
|
||||
}
|
||||
|
||||
func buildBearerTokens(key *ecdsa.PrivateKey, table *eacl.Table, gatesKeys []*ecdsa.PublicKey) ([]*token.BearerToken, error) {
|
||||
func buildBearerTokens(key *keys.PrivateKey, table *eacl.Table, gatesKeys []*keys.PublicKey) ([]*token.BearerToken, error) {
|
||||
bearerTokens := make([]*token.BearerToken, 0, len(gatesKeys))
|
||||
for _, gateKey := range gatesKeys {
|
||||
tkn, err := buildBearerToken(key, table, gateKey)
|
||||
|
@ -283,7 +283,7 @@ func buildBearerTokens(key *ecdsa.PrivateKey, table *eacl.Table, gatesKeys []*ec
|
|||
return bearerTokens, nil
|
||||
}
|
||||
|
||||
func buildSessionToken(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.ContainerContext, gateKey *ecdsa.PublicKey) (*session.Token, error) {
|
||||
func buildSessionToken(key *keys.PrivateKey, oid *owner.ID, ctx *session.ContainerContext, gateKey *keys.PublicKey) (*session.Token, error) {
|
||||
tok := session.NewToken()
|
||||
tok.SetContext(ctx)
|
||||
uid, err := uuid.New().MarshalBinary()
|
||||
|
@ -292,12 +292,12 @@ func buildSessionToken(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.Contai
|
|||
}
|
||||
tok.SetID(uid)
|
||||
tok.SetOwnerID(oid)
|
||||
tok.SetSessionKey(crypto.MarshalPublicKey(gateKey))
|
||||
tok.SetSessionKey(gateKey.Bytes())
|
||||
|
||||
return tok, tok.Sign(key)
|
||||
return tok, tok.Sign(&key.PrivateKey)
|
||||
}
|
||||
|
||||
func buildSessionTokens(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.ContainerContext, gatesKeys []*ecdsa.PublicKey) ([]*session.Token, error) {
|
||||
func buildSessionTokens(key *keys.PrivateKey, oid *owner.ID, ctx *session.ContainerContext, gatesKeys []*keys.PublicKey) ([]*session.Token, error) {
|
||||
sessionTokens := make([]*session.Token, 0, len(gatesKeys))
|
||||
for _, gateKey := range gatesKeys {
|
||||
tkn, err := buildSessionToken(key, oid, ctx, gateKey)
|
||||
|
@ -329,7 +329,7 @@ func createTokens(options *IssueSecretOptions, cid *cid.ID) ([]*accessbox.GateDa
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build context for session token: %w", err)
|
||||
}
|
||||
oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey)
|
||||
oid, err := ownerIDFromNeoFSKey(options.NeoFSKey.PublicKey())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -346,23 +346,10 @@ func createTokens(options *IssueSecretOptions, cid *cid.ID) ([]*accessbox.GateDa
|
|||
return gates, nil
|
||||
}
|
||||
|
||||
func ownerIDFromNeoFSKey(key *ecdsa.PublicKey) (*owner.ID, error) {
|
||||
wallet, err := owner.NEO3WalletFromPublicKey(key)
|
||||
func ownerIDFromNeoFSKey(key *keys.PublicKey) (*owner.ID, error) {
|
||||
wallet, err := owner.NEO3WalletFromPublicKey((*ecdsa.PublicKey)(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return owner.NewIDFromNeo3Wallet(wallet), nil
|
||||
}
|
||||
|
||||
// LoadPublicKey returns ecdsa.PublicKey from hex string.
|
||||
func LoadPublicKey(val string) (*ecdsa.PublicKey, error) {
|
||||
data, err := hex.DecodeString(val)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unknown key format (%q), expect: hex-string", val)
|
||||
}
|
||||
|
||||
if key := crypto.UnmarshalPublicKey(data); key != nil {
|
||||
return key, nil
|
||||
}
|
||||
return nil, fmt.Errorf("couldn't unmarshal public key (%q)", val)
|
||||
}
|
||||
|
|
|
@ -10,11 +10,13 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/authmate"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/internal/version"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/internal/wallet"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pkg/pool"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
@ -26,18 +28,25 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
neoFSKeyPathFlag string
|
||||
peerAddressFlag string
|
||||
eaclRulesFlag string
|
||||
contextRulesFlag string
|
||||
gatePrivateKeyFlag string
|
||||
accessKeyIDFlag string
|
||||
containerIDFlag string
|
||||
containerFriendlyName string
|
||||
gatesPublicKeysFlag cli.StringSlice
|
||||
logEnabledFlag bool
|
||||
logDebugEnabledFlag bool
|
||||
sessionTokenFlag bool
|
||||
walletPathFlag string
|
||||
accountAddressFlag string
|
||||
peerAddressFlag string
|
||||
eaclRulesFlag string
|
||||
contextRulesFlag string
|
||||
gateWalletPathFlag string
|
||||
gateAccountAddressFlag string
|
||||
accessKeyIDFlag string
|
||||
containerIDFlag string
|
||||
containerFriendlyName string
|
||||
gatesPublicKeysFlag cli.StringSlice
|
||||
logEnabledFlag bool
|
||||
logDebugEnabledFlag bool
|
||||
sessionTokenFlag bool
|
||||
)
|
||||
|
||||
const (
|
||||
envWalletPassphrase = "wallet.passphrase"
|
||||
envWalletGatePassphrase = "wallet.gate.passphrase"
|
||||
)
|
||||
|
||||
var zapConfig = zap.Config{
|
||||
|
@ -85,6 +94,11 @@ func main() {
|
|||
Commands: appCommands(),
|
||||
}
|
||||
|
||||
viper.AutomaticEnv()
|
||||
viper.SetEnvPrefix("AUTHMATE")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
viper.AllowEmptyEnv(true)
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "error: %s\n", err)
|
||||
os.Exit(100)
|
||||
|
@ -119,11 +133,18 @@ func issueSecret() *cli.Command {
|
|||
Usage: "Issue a secret in NeoFS network",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "neofs-key",
|
||||
Name: "wallet",
|
||||
Value: "",
|
||||
Usage: "path to owner's neofs private ecdsa key",
|
||||
Usage: "path to the wallet",
|
||||
Required: true,
|
||||
Destination: &neoFSKeyPathFlag,
|
||||
Destination: &walletPathFlag,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "address",
|
||||
Value: "",
|
||||
Usage: "address of wallet account",
|
||||
Required: false,
|
||||
Destination: &accountAddressFlag,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "peer",
|
||||
|
@ -174,7 +195,8 @@ func issueSecret() *cli.Command {
|
|||
Action: func(c *cli.Context) error {
|
||||
ctx, log := prepare()
|
||||
|
||||
key, err := crypto.LoadPrivateKey(neoFSKeyPathFlag)
|
||||
password := wallet.GetPassword(viper.GetViper(), envWalletPassphrase)
|
||||
key, err := wallet.GetKeyFromPath(walletPathFlag, accountAddressFlag, password)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to load neofs private key: %s", err), 1)
|
||||
}
|
||||
|
@ -182,7 +204,7 @@ func issueSecret() *cli.Command {
|
|||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
client, err := createSDKClient(ctx, log, key, peerAddressFlag)
|
||||
client, err := createSDKClient(ctx, log, &key.PrivateKey, peerAddressFlag)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to create sdk client: %s", err), 2)
|
||||
}
|
||||
|
@ -196,9 +218,9 @@ func issueSecret() *cli.Command {
|
|||
}
|
||||
}
|
||||
|
||||
var gatesPublicKeys []*ecdsa.PublicKey
|
||||
var gatesPublicKeys []*keys.PublicKey
|
||||
for _, key := range gatesPublicKeysFlag.Value() {
|
||||
gpk, err := authmate.LoadPublicKey(key)
|
||||
gpk, err := keys.NewPublicKeyFromString(key)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to load gate's public key: %s", err), 5)
|
||||
}
|
||||
|
@ -230,11 +252,18 @@ func obtainSecret() *cli.Command {
|
|||
Usage: "Obtain a secret from NeoFS network",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "neofs-key",
|
||||
Name: "wallet",
|
||||
Value: "",
|
||||
Usage: "path to owner's neofs private ecdsa key",
|
||||
Usage: "path to the wallet",
|
||||
Required: true,
|
||||
Destination: &neoFSKeyPathFlag,
|
||||
Destination: &walletPathFlag,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "address",
|
||||
Value: "",
|
||||
Usage: "address of wallet account",
|
||||
Required: false,
|
||||
Destination: &accountAddressFlag,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "peer",
|
||||
|
@ -244,10 +273,18 @@ func obtainSecret() *cli.Command {
|
|||
Destination: &peerAddressFlag,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "gate-private-key",
|
||||
Usage: "gate's private x25519 key",
|
||||
Name: "gate-wallet",
|
||||
Value: "",
|
||||
Usage: "path to the wallet",
|
||||
Required: true,
|
||||
Destination: &gatePrivateKeyFlag,
|
||||
Destination: &gateWalletPathFlag,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "gate-address",
|
||||
Value: "",
|
||||
Usage: "address of wallet account",
|
||||
Required: false,
|
||||
Destination: &gateAccountAddressFlag,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "access-key-id",
|
||||
|
@ -259,7 +296,8 @@ func obtainSecret() *cli.Command {
|
|||
Action: func(c *cli.Context) error {
|
||||
ctx, log := prepare()
|
||||
|
||||
key, err := crypto.LoadPrivateKey(neoFSKeyPathFlag)
|
||||
password := wallet.GetPassword(viper.GetViper(), envWalletPassphrase)
|
||||
key, err := wallet.GetKeyFromPath(walletPathFlag, accountAddressFlag, password)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to load neofs private key: %s", err), 1)
|
||||
}
|
||||
|
@ -267,7 +305,7 @@ func obtainSecret() *cli.Command {
|
|||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
client, err := createSDKClient(ctx, log, key, peerAddressFlag)
|
||||
client, err := createSDKClient(ctx, log, &key.PrivateKey, peerAddressFlag)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to create sdk client: %s", err), 2)
|
||||
}
|
||||
|
@ -276,7 +314,8 @@ func obtainSecret() *cli.Command {
|
|||
|
||||
var _ = agent
|
||||
|
||||
gateCreds, err := crypto.LoadPrivateKey(gatePrivateKeyFlag)
|
||||
password = wallet.GetPassword(viper.GetViper(), envWalletGatePassphrase)
|
||||
gateCreds, err := wallet.GetKeyFromPath(gateWalletPathFlag, gateAccountAddressFlag, password)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to create owner's private key: %s", err), 4)
|
||||
}
|
||||
|
|
|
@ -151,6 +151,7 @@ func newSettings() *viper.Viper {
|
|||
v.SetEnvPrefix(envPrefix)
|
||||
v.SetConfigType("yaml")
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
v.AllowEmptyEnv(true)
|
||||
|
||||
// flags setup:
|
||||
flags := pflag.NewFlagSet("commandline", pflag.ExitOnError)
|
||||
|
|
|
@ -3,20 +3,16 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/api"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/api/auth"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/api/handler"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/internal/wallet"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pkg/pool"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
|
@ -85,12 +81,8 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
|
|||
reBalance = v
|
||||
}
|
||||
|
||||
var password *string
|
||||
if v.IsSet(cfgWalletPassphrase) {
|
||||
pwd := v.GetString(cfgWalletPassphrase)
|
||||
password = &pwd
|
||||
}
|
||||
if key, err = getKeyFromWallet(v.GetString(cfgWallet), v.GetString(cfgAddress), password); err != nil {
|
||||
password := wallet.GetPassword(v, cfgWalletPassphrase)
|
||||
if key, err = wallet.GetKeyFromPath(v.GetString(cfgWallet), v.GetString(cfgAddress), password); err != nil {
|
||||
l.Fatal("could not load NeoFS private key", zap.Error(err))
|
||||
}
|
||||
|
||||
|
@ -120,7 +112,7 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
|
|||
obj = layer.NewLayer(l, conns)
|
||||
|
||||
// prepare auth center
|
||||
ctr = auth.New(conns, &key.PrivateKey)
|
||||
ctr = auth.New(conns, key)
|
||||
|
||||
if caller, err = handler.New(l, obj); err != nil {
|
||||
l.Fatal("could not initialize API handler", zap.Error(err))
|
||||
|
@ -142,44 +134,6 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
|
|||
}
|
||||
}
|
||||
|
||||
func getKeyFromWallet(walletPath, addrStr string, password *string) (*keys.PrivateKey, error) {
|
||||
if len(walletPath) == 0 {
|
||||
return nil, fmt.Errorf("wallet path must not be empty")
|
||||
}
|
||||
w, err := wallet.NewWalletFromFile(walletPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var addr util.Uint160
|
||||
if len(addrStr) == 0 {
|
||||
addr = w.GetChangeAddress()
|
||||
} else {
|
||||
addr, err = flags.ParseAddress(addrStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid address")
|
||||
}
|
||||
}
|
||||
|
||||
acc := w.GetAccount(addr)
|
||||
if acc == nil {
|
||||
return nil, fmt.Errorf("couldn't find wallet account for %s", addrStr)
|
||||
}
|
||||
|
||||
if password == nil {
|
||||
pwd, err := input.ReadPassword("Enter password > ")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't read password")
|
||||
}
|
||||
password = &pwd
|
||||
}
|
||||
if err := acc.Decrypt(*password, w.Scrypt); err != nil {
|
||||
return nil, fmt.Errorf("couldn't decrypt account: %w", err)
|
||||
}
|
||||
|
||||
return acc.PrivateKey(), nil
|
||||
}
|
||||
|
||||
// Wait waits for application to finish.
|
||||
func (a *App) Wait() {
|
||||
a.log.Info("application started")
|
||||
|
|
|
@ -3,7 +3,6 @@ package accessbox
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
|
@ -11,9 +10,9 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/session"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/token"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
@ -24,18 +23,18 @@ type GateData struct {
|
|||
AccessKey string
|
||||
BearerToken *token.BearerToken
|
||||
SessionToken *session.Token
|
||||
GateKey *ecdsa.PublicKey
|
||||
GateKey *keys.PublicKey
|
||||
}
|
||||
|
||||
// NewGateData returns GateData from provided bearer token and public gate key.
|
||||
func NewGateData(gateKey *ecdsa.PublicKey, bearerTkn *token.BearerToken) *GateData {
|
||||
func NewGateData(gateKey *keys.PublicKey, bearerTkn *token.BearerToken) *GateData {
|
||||
return &GateData{GateKey: gateKey, BearerToken: bearerTkn}
|
||||
}
|
||||
|
||||
// Secrets represents AccessKey and key to encrypt gate tokens.
|
||||
type Secrets struct {
|
||||
AccessKey string
|
||||
EphemeralKey *ecdsa.PrivateKey
|
||||
EphemeralKey *keys.PrivateKey
|
||||
}
|
||||
|
||||
// Marshal returns the wire-format of AccessBox.
|
||||
|
@ -52,11 +51,11 @@ func (x *AccessBox) Unmarshal(data []byte) error {
|
|||
// Session token can be nil.
|
||||
func PackTokens(gatesData []*GateData) (*AccessBox, *Secrets, error) {
|
||||
box := &AccessBox{}
|
||||
ephemeralKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
ephemeralKey, err := keys.NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
box.OwnerPublicKey = crypto.MarshalPublicKey(&ephemeralKey.PublicKey)
|
||||
box.OwnerPublicKey = ephemeralKey.PublicKey().Bytes()
|
||||
|
||||
secret, err := generateSecret()
|
||||
if err != nil {
|
||||
|
@ -71,9 +70,12 @@ func PackTokens(gatesData []*GateData) (*AccessBox, *Secrets, error) {
|
|||
}
|
||||
|
||||
// GetTokens returns gate tokens from AccessBox.
|
||||
func (x *AccessBox) GetTokens(owner *ecdsa.PrivateKey) (*GateData, error) {
|
||||
sender := crypto.UnmarshalPublicKey(x.OwnerPublicKey)
|
||||
ownerKey := crypto.MarshalPublicKey(&owner.PublicKey)
|
||||
func (x *AccessBox) GetTokens(owner *keys.PrivateKey) (*GateData, error) {
|
||||
sender, err := keys.NewPublicKeyFromBytes(x.OwnerPublicKey, elliptic.P256())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't unmarshal OwnerPublicKey: %w", err)
|
||||
}
|
||||
ownerKey := owner.PublicKey().Bytes()
|
||||
for _, gate := range x.Gates {
|
||||
if !bytes.Equal(gate.GatePublicKey, ownerKey) {
|
||||
continue
|
||||
|
@ -89,7 +91,7 @@ func (x *AccessBox) GetTokens(owner *ecdsa.PrivateKey) (*GateData, error) {
|
|||
return nil, fmt.Errorf("no gate data for key %x was found", ownerKey)
|
||||
}
|
||||
|
||||
func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *ecdsa.PrivateKey, secret []byte) error {
|
||||
func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *keys.PrivateKey, secret []byte) error {
|
||||
for i, gate := range gatesData {
|
||||
encBearer, err := gate.BearerToken.Marshal()
|
||||
if err != nil {
|
||||
|
@ -117,7 +119,7 @@ func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *ecdsa.Private
|
|||
return nil
|
||||
}
|
||||
|
||||
func encodeGate(ephemeralKey *ecdsa.PrivateKey, ownerKey *ecdsa.PublicKey, tokens *Tokens) (*AccessBox_Gate, error) {
|
||||
func encodeGate(ephemeralKey *keys.PrivateKey, ownerKey *keys.PublicKey, tokens *Tokens) (*AccessBox_Gate, error) {
|
||||
data, err := proto.Marshal(tokens)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -129,12 +131,12 @@ func encodeGate(ephemeralKey *ecdsa.PrivateKey, ownerKey *ecdsa.PublicKey, token
|
|||
}
|
||||
|
||||
gate := new(AccessBox_Gate)
|
||||
gate.GatePublicKey = crypto.MarshalPublicKey(ownerKey)
|
||||
gate.GatePublicKey = ownerKey.Bytes()
|
||||
gate.Tokens = encrypted
|
||||
return gate, nil
|
||||
}
|
||||
|
||||
func decodeGate(gate *AccessBox_Gate, owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) (*GateData, error) {
|
||||
func decodeGate(gate *AccessBox_Gate, owner *keys.PrivateKey, sender *keys.PublicKey) (*GateData, error) {
|
||||
data, err := decrypt(owner, sender, gate.Tokens)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -153,14 +155,14 @@ func decodeGate(gate *AccessBox_Gate, owner *ecdsa.PrivateKey, sender *ecdsa.Pub
|
|||
return nil, err
|
||||
}
|
||||
|
||||
gateData := NewGateData(&owner.PublicKey, bearerTkn)
|
||||
gateData := NewGateData(owner.PublicKey(), bearerTkn)
|
||||
gateData.SessionToken = sessionTkn
|
||||
gateData.AccessKey = hex.EncodeToString(tokens.AccessKey)
|
||||
return gateData, nil
|
||||
}
|
||||
|
||||
func generateShared256(prv *ecdsa.PrivateKey, pub *ecdsa.PublicKey) (sk []byte, err error) {
|
||||
if prv.PublicKey.Curve != pub.Curve {
|
||||
func generateShared256(prv *keys.PrivateKey, pub *keys.PublicKey) (sk []byte, err error) {
|
||||
if prv.PublicKey().Curve != pub.Curve {
|
||||
return nil, fmt.Errorf("not equal curves")
|
||||
}
|
||||
|
||||
|
@ -183,7 +185,7 @@ func deriveKey(secret []byte) ([]byte, error) {
|
|||
return key, err
|
||||
}
|
||||
|
||||
func encrypt(owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey, data []byte) ([]byte, error) {
|
||||
func encrypt(owner *keys.PrivateKey, sender *keys.PublicKey, data []byte) ([]byte, error) {
|
||||
enc, err := getCipher(owner, sender)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -197,7 +199,7 @@ func encrypt(owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey, data []byte) ([]b
|
|||
return enc.Seal(nonce, nonce, data, nil), nil
|
||||
}
|
||||
|
||||
func decrypt(owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey, data []byte) ([]byte, error) {
|
||||
func decrypt(owner *keys.PrivateKey, sender *keys.PublicKey, data []byte) ([]byte, error) {
|
||||
dec, err := getCipher(owner, sender)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -211,7 +213,7 @@ func decrypt(owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey, data []byte) ([]b
|
|||
return dec.Open(nil, nonce, cypher, nil)
|
||||
}
|
||||
|
||||
func getCipher(owner *ecdsa.PrivateKey, sender *ecdsa.PublicKey) (cipher.AEAD, error) {
|
||||
func getCipher(owner *keys.PrivateKey, sender *keys.PublicKey) (cipher.AEAD, error) {
|
||||
secret, err := generateShared256(owner, sender)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
package accessbox
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/session"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/token"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -19,22 +16,22 @@ func Test_tokens_encrypt_decrypt(t *testing.T) {
|
|||
tkn = token.NewBearerToken()
|
||||
tkn2 = token.NewBearerToken()
|
||||
)
|
||||
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
sec, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
cred, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
tkn.SetEACLTable(eacl.NewTable())
|
||||
require.NoError(t, tkn.SignToken(sec))
|
||||
require.NoError(t, tkn.SignToken(&sec.PrivateKey))
|
||||
|
||||
rawTkn, err := tkn.Marshal()
|
||||
require.NoError(t, err)
|
||||
|
||||
data, err := encrypt(cred, &cred.PublicKey, rawTkn)
|
||||
data, err := encrypt(cred, cred.PublicKey(), rawTkn)
|
||||
require.NoError(t, err)
|
||||
|
||||
rawTkn2, err := decrypt(cred, &cred.PublicKey, data)
|
||||
rawTkn2, err := decrypt(cred, cred.PublicKey(), data)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = tkn2.Unmarshal(rawTkn2)
|
||||
|
@ -50,16 +47,16 @@ func Test_bearer_token_in_access_box(t *testing.T) {
|
|||
tkn = token.NewBearerToken()
|
||||
)
|
||||
|
||||
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
sec, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
cred, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
tkn.SetEACLTable(eacl.NewTable())
|
||||
require.NoError(t, tkn.SignToken(sec))
|
||||
require.NoError(t, tkn.SignToken(&sec.PrivateKey))
|
||||
|
||||
gate := NewGateData(&cred.PublicKey, tkn)
|
||||
gate := NewGateData(cred.PublicKey(), tkn)
|
||||
box, _, err = PackTokens([]*GateData{gate})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -82,10 +79,10 @@ func Test_session_token_in_access_box(t *testing.T) {
|
|||
tkn = session.NewToken()
|
||||
)
|
||||
|
||||
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
sec, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
cred, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
tok := session.NewToken()
|
||||
|
@ -93,10 +90,10 @@ func Test_session_token_in_access_box(t *testing.T) {
|
|||
uid, err := uuid.New().MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
tok.SetID(uid)
|
||||
tok.SetSessionKey(crypto.MarshalPublicKey(&sec.PublicKey))
|
||||
require.NoError(t, tkn.Sign(sec))
|
||||
tok.SetSessionKey(sec.PublicKey().Bytes())
|
||||
require.NoError(t, tkn.Sign(&sec.PrivateKey))
|
||||
|
||||
gate := NewGateData(&cred.PublicKey, token.NewBearerToken())
|
||||
gate := NewGateData(cred.PublicKey(), token.NewBearerToken())
|
||||
gate.SessionToken = tkn
|
||||
box, _, err = PackTokens([]*GateData{gate})
|
||||
require.NoError(t, err)
|
||||
|
@ -119,29 +116,29 @@ func Test_accessbox_multiple_keys(t *testing.T) {
|
|||
tkn = token.NewBearerToken()
|
||||
)
|
||||
|
||||
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
sec, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
tkn.SetEACLTable(eacl.NewTable())
|
||||
require.NoError(t, tkn.SignToken(sec))
|
||||
require.NoError(t, tkn.SignToken(&sec.PrivateKey))
|
||||
|
||||
count := 10
|
||||
gates := make([]*GateData, 0, count)
|
||||
keys := make([]*ecdsa.PrivateKey, 0, count)
|
||||
privateKeys := make([]*keys.PrivateKey, 0, count)
|
||||
{ // generate keys
|
||||
for i := 0; i < count; i++ {
|
||||
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
cred, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
gates = append(gates, NewGateData(&cred.PublicKey, tkn))
|
||||
keys = append(keys, cred)
|
||||
gates = append(gates, NewGateData(cred.PublicKey(), tkn))
|
||||
privateKeys = append(privateKeys, cred)
|
||||
}
|
||||
}
|
||||
|
||||
box, _, err = PackTokens(gates)
|
||||
require.NoError(t, err)
|
||||
|
||||
for i, k := range keys {
|
||||
for i, k := range privateKeys {
|
||||
tkns, err := box.GetTokens(k)
|
||||
require.NoError(t, err, "key #%d: %s failed", i, k)
|
||||
require.Equal(t, tkns.BearerToken, tkn)
|
||||
|
@ -154,19 +151,19 @@ func Test_unknown_key(t *testing.T) {
|
|||
tkn = token.NewBearerToken()
|
||||
)
|
||||
|
||||
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
sec, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
cred, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
wrongCred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
wrongCred, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
tkn.SetEACLTable(eacl.NewTable())
|
||||
require.NoError(t, tkn.SignToken(sec))
|
||||
require.NoError(t, tkn.SignToken(&sec.PrivateKey))
|
||||
|
||||
gate := NewGateData(&cred.PublicKey, tkn)
|
||||
gate := NewGateData(cred.PublicKey(), tkn)
|
||||
box, _, err = PackTokens([]*GateData{gate})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
|
@ -3,12 +3,12 @@ package tokens
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/client"
|
||||
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||
|
@ -21,11 +21,11 @@ type (
|
|||
// Credentials is a bearer token get/put interface.
|
||||
Credentials interface {
|
||||
GetTokens(context.Context, *object.Address) (*accessbox.GateData, error)
|
||||
Put(context.Context, *cid.ID, *owner.ID, *accessbox.AccessBox, ...*ecdsa.PublicKey) (*object.Address, error)
|
||||
Put(context.Context, *cid.ID, *owner.ID, *accessbox.AccessBox, ...*keys.PublicKey) (*object.Address, error)
|
||||
}
|
||||
|
||||
cred struct {
|
||||
key *ecdsa.PrivateKey
|
||||
key *keys.PrivateKey
|
||||
pool pool.Pool
|
||||
}
|
||||
)
|
||||
|
@ -46,7 +46,7 @@ var bufferPool = sync.Pool{
|
|||
var _ = New
|
||||
|
||||
// New creates new Credentials instance using given cli and key.
|
||||
func New(conns pool.Pool, key *ecdsa.PrivateKey) Credentials {
|
||||
func New(conns pool.Pool, key *keys.PrivateKey) Credentials {
|
||||
return &cred{pool: conns, key: key}
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*acce
|
|||
return &box, nil
|
||||
}
|
||||
|
||||
func (c *cred) Put(ctx context.Context, cid *cid.ID, issuer *owner.ID, box *accessbox.AccessBox, keys ...*ecdsa.PublicKey) (*object.Address, error) {
|
||||
func (c *cred) Put(ctx context.Context, cid *cid.ID, issuer *owner.ID, box *accessbox.AccessBox, keys ...*keys.PublicKey) (*object.Address, error) {
|
||||
var (
|
||||
err error
|
||||
created = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
|
|
1
go.mod
1
go.mod
|
@ -9,7 +9,6 @@ require (
|
|||
github.com/gorilla/mux v1.8.0
|
||||
github.com/nspcc-dev/neo-go v0.95.3
|
||||
github.com/nspcc-dev/neofs-api-go v1.27.1
|
||||
github.com/nspcc-dev/neofs-crypto v0.3.0
|
||||
github.com/nspcc-dev/neofs-node v1.22.0
|
||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20210624072335-0348eb331c92
|
||||
github.com/prometheus/client_golang v1.9.0
|
||||
|
|
61
internal/wallet/wallet.go
Normal file
61
internal/wallet/wallet.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
package wallet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// GetPassword gets passphrase for wallet.
|
||||
func GetPassword(v *viper.Viper, variable string) *string {
|
||||
var password *string
|
||||
if v.IsSet(variable) {
|
||||
pwd := v.GetString(variable)
|
||||
password = &pwd
|
||||
}
|
||||
return password
|
||||
}
|
||||
|
||||
// GetKeyFromPath reads wallet and gets private key.
|
||||
func GetKeyFromPath(walletPath, addrStr string, password *string) (*keys.PrivateKey, error) {
|
||||
if len(walletPath) == 0 {
|
||||
return nil, fmt.Errorf("wallet path must not be empty")
|
||||
}
|
||||
w, err := wallet.NewWalletFromFile(walletPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var addr util.Uint160
|
||||
if len(addrStr) == 0 {
|
||||
addr = w.GetChangeAddress()
|
||||
} else {
|
||||
addr, err = flags.ParseAddress(addrStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid address")
|
||||
}
|
||||
}
|
||||
|
||||
acc := w.GetAccount(addr)
|
||||
if acc == nil {
|
||||
return nil, fmt.Errorf("couldn't find wallet account for %s", addrStr)
|
||||
}
|
||||
|
||||
if password == nil {
|
||||
pwd, err := input.ReadPassword(fmt.Sprintf("Enter password for %s > ", walletPath))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't read password")
|
||||
}
|
||||
password = &pwd
|
||||
}
|
||||
if err := acc.Decrypt(*password, w.Scrypt); err != nil {
|
||||
return nil, fmt.Errorf("couldn't decrypt account: %w", err)
|
||||
}
|
||||
|
||||
return acc.PrivateKey(), nil
|
||||
}
|
Loading…
Reference in a new issue