[#104] Support NEP-6 for authmate

Drop neofs-crypto.

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2021-06-24 18:21:34 +03:00
parent 39a43c21a1
commit 52c63d4c44
11 changed files with 227 additions and 172 deletions

View file

@ -109,7 +109,7 @@ default. To enable them use `--pprof` and `--metrics` flags or
## NeoFS AuthMate ## 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 are authenticated with access key IDs and secrets, while NeoFS users are
authenticated with key pairs. To complicate things further we have S3 gateway 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 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 "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 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 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 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 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 to read and it needs to be encrypted with this gateway's key (among others
potentially). 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 #### Generation of wallet
To generate wallets for gateways, run the following command: 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: 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 \ --peer 192.168.130.71:8080 \
--bearer-rules '{"records":[{"operation":"PUT","action":"ALLOW","filters":[],"targets":[{"role":"OTHERS","keys":[]}]}]}' \ --bearer-rules '{"records":[{"operation":"PUT","action":"ALLOW","filters":[],"targets":[{"role":"OTHERS","keys":[]}]}]}' \
--gate-public-key dd34f6dce9a4ce0990869ec6bd33a40e102a5798881cfe61d03a5659ceee1a64 \ --gate-public-key dd34f6dce9a4ce0990869ec6bd33a40e102a5798881cfe61d03a5659ceee1a64 \
@ -242,6 +253,7 @@ $ ./neofs-authmate issue-secret --neofs-key user.key \
--create-session-token \ --create-session-token \
--session-rules '{"verb":"DELETE","wildcard":false,"containerID":{"value":"%CID"}}' --session-rules '{"verb":"DELETE","wildcard":false,"containerID":{"value":"%CID"}}'
Enter password for wallet.json >
{ {
"access_key_id": "5g933dyLEkXbbAspouhPPTiyLZRg4axBW1axSPD87eVT_AiXsH4AjYy1iTJ4C1WExzjBrSobJsQFWEyKLREe5sQYM", "access_key_id": "5g933dyLEkXbbAspouhPPTiyLZRg4axBW1axSPD87eVT_AiXsH4AjYy1iTJ4C1WExzjBrSobJsQFWEyKLREe5sQYM",
"secret_access_key": "438bbd8243060e1e1c9dd4821756914a6e872ce29bf203b68f81b140ac91231c", "secret_access_key": "438bbd8243060e1e1c9dd4821756914a6e872ce29bf203b68f81b140ac91231c",
@ -255,14 +267,17 @@ any S3 client.
#### Obtainment of a secret access key #### Obtainment of a secret access key
You can get a secret access key associated with access key ID by obtaining a 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 \ --peer 192.168.130.71:8080 \
--gate-private-key b8ba980eb70b959be99915d2e0ad377809984ccd1dac0a6551907f81c2b33d21 \ --gate-wallet gate-wallet.json \
--access-key-id 5g933dyLEkXbbAspouhPPTiyLZRg4axBW1axSPD87eVT_AiXsH4AjYy1iTJ4C1WExzjBrSobJsQFWEyKLREe5sQYM --access-key-id 5g933dyLEkXbbAspouhPPTiyLZRg4axBW1axSPD87eVT_AiXsH4AjYy1iTJ4C1WExzjBrSobJsQFWEyKLREe5sQYM
Enter password for gate-wallet.json >
{ {
"secret_access_key": "438bbd8243060e1e1c9dd4821756914a6e872ce29bf203b68f81b140ac91231c" "secret_access_key": "438bbd8243060e1e1c9dd4821756914a6e872ce29bf203b68f81b140ac91231c"
} }

View file

@ -2,7 +2,6 @@ package auth
import ( import (
"context" "context"
"crypto/ecdsa"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -13,6 +12,7 @@ import (
"github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
v4 "github.com/aws/aws-sdk-go/aws/signer/v4" 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-api-go/pkg/object"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox" "github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
"github.com/nspcc-dev/neofs-s3-gw/creds/tokens" "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) var _ io.ReadSeeker = prs(0)
// New creates an instance of AuthCenter. // 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 &center{ return &center{
cli: tokens.New(conns, key), cli: tokens.New(conns, key),
reg: &regexpSubmatcher{re: authorizationFieldRegexp}, reg: &regexpSubmatcher{re: authorizationFieldRegexp},

View file

@ -12,6 +12,7 @@ import (
"time" "time"
"github.com/google/uuid" "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/acl/eacl"
"github.com/nspcc-dev/neofs-api-go/pkg/container" "github.com/nspcc-dev/neofs-api-go/pkg/container"
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id" 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/owner"
"github.com/nspcc-dev/neofs-api-go/pkg/session" "github.com/nspcc-dev/neofs-api-go/pkg/session"
"github.com/nspcc-dev/neofs-api-go/pkg/token" "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-node/pkg/policy"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox" "github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
"github.com/nspcc-dev/neofs-s3-gw/creds/tokens" "github.com/nspcc-dev/neofs-s3-gw/creds/tokens"
@ -48,8 +48,8 @@ type (
IssueSecretOptions struct { IssueSecretOptions struct {
ContainerID *cid.ID ContainerID *cid.ID
ContainerFriendlyName string ContainerFriendlyName string
NeoFSKey *ecdsa.PrivateKey NeoFSKey *keys.PrivateKey
GatesPublicKeys []*ecdsa.PublicKey GatesPublicKeys []*keys.PublicKey
EACLRules []byte EACLRules []byte
ContextRules []byte ContextRules []byte
SessionTkn bool SessionTkn bool
@ -58,7 +58,7 @@ type (
// ObtainSecretOptions contains options for passing to Agent.ObtainSecret method. // ObtainSecretOptions contains options for passing to Agent.ObtainSecret method.
ObtainSecretOptions struct { ObtainSecretOptions struct {
SecretAddress string 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 return err
} }
oid, err := ownerIDFromNeoFSKey(&options.NeoFSKey.PublicKey) oid, err := ownerIDFromNeoFSKey(options.NeoFSKey.PublicKey())
if err != nil { if err != nil {
return err return err
} }
@ -155,7 +155,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
ir := &issuingResult{ ir := &issuingResult{
AccessKeyID: accessKeyID, AccessKeyID: accessKeyID,
SecretAccessKey: secrets.AccessKey, SecretAccessKey: secrets.AccessKey,
OwnerPrivateKey: hex.EncodeToString(crypto.MarshalPrivateKey(secrets.EphemeralKey)), OwnerPrivateKey: hex.EncodeToString(secrets.EphemeralKey.Bytes()),
} }
enc := json.NewEncoder(w) enc := json.NewEncoder(w)
@ -257,7 +257,7 @@ func buildContext(rules []byte) (*session.ContainerContext, error) {
return sessionCtx, nil 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) oid, err := ownerIDFromNeoFSKey(gateKey)
if err != nil { if err != nil {
return nil, err return nil, err
@ -268,10 +268,10 @@ func buildBearerToken(key *ecdsa.PrivateKey, table *eacl.Table, gateKey *ecdsa.P
bearerToken.SetOwner(oid) bearerToken.SetOwner(oid)
bearerToken.SetLifetime(math.MaxUint64, 0, 0) 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)) bearerTokens := make([]*token.BearerToken, 0, len(gatesKeys))
for _, gateKey := range gatesKeys { for _, gateKey := range gatesKeys {
tkn, err := buildBearerToken(key, table, gateKey) tkn, err := buildBearerToken(key, table, gateKey)
@ -283,7 +283,7 @@ func buildBearerTokens(key *ecdsa.PrivateKey, table *eacl.Table, gatesKeys []*ec
return bearerTokens, nil 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 := session.NewToken()
tok.SetContext(ctx) tok.SetContext(ctx)
uid, err := uuid.New().MarshalBinary() uid, err := uuid.New().MarshalBinary()
@ -292,12 +292,12 @@ func buildSessionToken(key *ecdsa.PrivateKey, oid *owner.ID, ctx *session.Contai
} }
tok.SetID(uid) tok.SetID(uid)
tok.SetOwnerID(oid) 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)) sessionTokens := make([]*session.Token, 0, len(gatesKeys))
for _, gateKey := range gatesKeys { for _, gateKey := range gatesKeys {
tkn, err := buildSessionToken(key, oid, ctx, gateKey) tkn, err := buildSessionToken(key, oid, ctx, gateKey)
@ -329,7 +329,7 @@ func createTokens(options *IssueSecretOptions, cid *cid.ID) ([]*accessbox.GateDa
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to build context for session token: %w", err) 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 { if err != nil {
return nil, err return nil, err
} }
@ -346,23 +346,10 @@ func createTokens(options *IssueSecretOptions, cid *cid.ID) ([]*accessbox.GateDa
return gates, nil return gates, nil
} }
func ownerIDFromNeoFSKey(key *ecdsa.PublicKey) (*owner.ID, error) { func ownerIDFromNeoFSKey(key *keys.PublicKey) (*owner.ID, error) {
wallet, err := owner.NEO3WalletFromPublicKey(key) wallet, err := owner.NEO3WalletFromPublicKey((*ecdsa.PublicKey)(key))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return owner.NewIDFromNeo3Wallet(wallet), nil 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)
}

View file

@ -10,11 +10,13 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id" 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/authmate"
"github.com/nspcc-dev/neofs-s3-gw/internal/version" "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/nspcc-dev/neofs-sdk-go/pkg/pool"
"github.com/spf13/viper"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
@ -26,18 +28,25 @@ const (
) )
var ( var (
neoFSKeyPathFlag string walletPathFlag string
peerAddressFlag string accountAddressFlag string
eaclRulesFlag string peerAddressFlag string
contextRulesFlag string eaclRulesFlag string
gatePrivateKeyFlag string contextRulesFlag string
accessKeyIDFlag string gateWalletPathFlag string
containerIDFlag string gateAccountAddressFlag string
containerFriendlyName string accessKeyIDFlag string
gatesPublicKeysFlag cli.StringSlice containerIDFlag string
logEnabledFlag bool containerFriendlyName string
logDebugEnabledFlag bool gatesPublicKeysFlag cli.StringSlice
sessionTokenFlag bool logEnabledFlag bool
logDebugEnabledFlag bool
sessionTokenFlag bool
)
const (
envWalletPassphrase = "wallet.passphrase"
envWalletGatePassphrase = "wallet.gate.passphrase"
) )
var zapConfig = zap.Config{ var zapConfig = zap.Config{
@ -85,6 +94,11 @@ func main() {
Commands: appCommands(), Commands: appCommands(),
} }
viper.AutomaticEnv()
viper.SetEnvPrefix("AUTHMATE")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AllowEmptyEnv(true)
if err := app.Run(os.Args); err != nil { if err := app.Run(os.Args); err != nil {
_, _ = fmt.Fprintf(os.Stderr, "error: %s\n", err) _, _ = fmt.Fprintf(os.Stderr, "error: %s\n", err)
os.Exit(100) os.Exit(100)
@ -119,11 +133,18 @@ func issueSecret() *cli.Command {
Usage: "Issue a secret in NeoFS network", Usage: "Issue a secret in NeoFS network",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "neofs-key", Name: "wallet",
Value: "", Value: "",
Usage: "path to owner's neofs private ecdsa key", Usage: "path to the wallet",
Required: true, Required: true,
Destination: &neoFSKeyPathFlag, Destination: &walletPathFlag,
},
&cli.StringFlag{
Name: "address",
Value: "",
Usage: "address of wallet account",
Required: false,
Destination: &accountAddressFlag,
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "peer", Name: "peer",
@ -174,7 +195,8 @@ func issueSecret() *cli.Command {
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
ctx, log := prepare() ctx, log := prepare()
key, err := crypto.LoadPrivateKey(neoFSKeyPathFlag) password := wallet.GetPassword(viper.GetViper(), envWalletPassphrase)
key, err := wallet.GetKeyFromPath(walletPathFlag, accountAddressFlag, password)
if err != nil { if err != nil {
return cli.Exit(fmt.Sprintf("failed to load neofs private key: %s", err), 1) 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) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
client, err := createSDKClient(ctx, log, key, peerAddressFlag) client, err := createSDKClient(ctx, log, &key.PrivateKey, peerAddressFlag)
if err != nil { if err != nil {
return cli.Exit(fmt.Sprintf("failed to create sdk client: %s", err), 2) 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() { for _, key := range gatesPublicKeysFlag.Value() {
gpk, err := authmate.LoadPublicKey(key) gpk, err := keys.NewPublicKeyFromString(key)
if err != nil { if err != nil {
return cli.Exit(fmt.Sprintf("failed to load gate's public key: %s", err), 5) 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", Usage: "Obtain a secret from NeoFS network",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "neofs-key", Name: "wallet",
Value: "", Value: "",
Usage: "path to owner's neofs private ecdsa key", Usage: "path to the wallet",
Required: true, Required: true,
Destination: &neoFSKeyPathFlag, Destination: &walletPathFlag,
},
&cli.StringFlag{
Name: "address",
Value: "",
Usage: "address of wallet account",
Required: false,
Destination: &accountAddressFlag,
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "peer", Name: "peer",
@ -244,10 +273,18 @@ func obtainSecret() *cli.Command {
Destination: &peerAddressFlag, Destination: &peerAddressFlag,
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "gate-private-key", Name: "gate-wallet",
Usage: "gate's private x25519 key", Value: "",
Usage: "path to the wallet",
Required: true, Required: true,
Destination: &gatePrivateKeyFlag, Destination: &gateWalletPathFlag,
},
&cli.StringFlag{
Name: "gate-address",
Value: "",
Usage: "address of wallet account",
Required: false,
Destination: &gateAccountAddressFlag,
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "access-key-id", Name: "access-key-id",
@ -259,7 +296,8 @@ func obtainSecret() *cli.Command {
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
ctx, log := prepare() ctx, log := prepare()
key, err := crypto.LoadPrivateKey(neoFSKeyPathFlag) password := wallet.GetPassword(viper.GetViper(), envWalletPassphrase)
key, err := wallet.GetKeyFromPath(walletPathFlag, accountAddressFlag, password)
if err != nil { if err != nil {
return cli.Exit(fmt.Sprintf("failed to load neofs private key: %s", err), 1) 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) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
client, err := createSDKClient(ctx, log, key, peerAddressFlag) client, err := createSDKClient(ctx, log, &key.PrivateKey, peerAddressFlag)
if err != nil { if err != nil {
return cli.Exit(fmt.Sprintf("failed to create sdk client: %s", err), 2) return cli.Exit(fmt.Sprintf("failed to create sdk client: %s", err), 2)
} }
@ -276,7 +314,8 @@ func obtainSecret() *cli.Command {
var _ = agent var _ = agent
gateCreds, err := crypto.LoadPrivateKey(gatePrivateKeyFlag) password = wallet.GetPassword(viper.GetViper(), envWalletGatePassphrase)
gateCreds, err := wallet.GetKeyFromPath(gateWalletPathFlag, gateAccountAddressFlag, password)
if err != nil { if err != nil {
return cli.Exit(fmt.Sprintf("failed to create owner's private key: %s", err), 4) return cli.Exit(fmt.Sprintf("failed to create owner's private key: %s", err), 4)
} }

View file

@ -151,6 +151,7 @@ func newSettings() *viper.Viper {
v.SetEnvPrefix(envPrefix) v.SetEnvPrefix(envPrefix)
v.SetConfigType("yaml") v.SetConfigType("yaml")
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
v.AllowEmptyEnv(true)
// flags setup: // flags setup:
flags := pflag.NewFlagSet("commandline", pflag.ExitOnError) flags := pflag.NewFlagSet("commandline", pflag.ExitOnError)

View file

@ -3,20 +3,16 @@ package main
import ( import (
"context" "context"
"encoding/hex" "encoding/hex"
"fmt"
"math" "math"
"net" "net"
"net/http" "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/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"
"github.com/nspcc-dev/neofs-s3-gw/api/auth" "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/handler"
"github.com/nspcc-dev/neofs-s3-gw/api/layer" "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/nspcc-dev/neofs-sdk-go/pkg/pool"
"github.com/spf13/viper" "github.com/spf13/viper"
"go.uber.org/zap" "go.uber.org/zap"
@ -85,12 +81,8 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
reBalance = v reBalance = v
} }
var password *string password := wallet.GetPassword(v, cfgWalletPassphrase)
if v.IsSet(cfgWalletPassphrase) { if key, err = wallet.GetKeyFromPath(v.GetString(cfgWallet), v.GetString(cfgAddress), password); err != nil {
pwd := v.GetString(cfgWalletPassphrase)
password = &pwd
}
if key, err = getKeyFromWallet(v.GetString(cfgWallet), v.GetString(cfgAddress), password); err != nil {
l.Fatal("could not load NeoFS private key", zap.Error(err)) 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) obj = layer.NewLayer(l, conns)
// prepare auth center // prepare auth center
ctr = auth.New(conns, &key.PrivateKey) ctr = auth.New(conns, key)
if caller, err = handler.New(l, obj); err != nil { if caller, err = handler.New(l, obj); err != nil {
l.Fatal("could not initialize API handler", zap.Error(err)) 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. // Wait waits for application to finish.
func (a *App) Wait() { func (a *App) Wait() {
a.log.Info("application started") a.log.Info("application started")

View file

@ -3,7 +3,6 @@ package accessbox
import ( import (
"bytes" "bytes"
"crypto/cipher" "crypto/cipher"
"crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
@ -11,9 +10,9 @@ import (
"fmt" "fmt"
"io" "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/session"
"github.com/nspcc-dev/neofs-api-go/pkg/token" "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/chacha20poly1305"
"golang.org/x/crypto/hkdf" "golang.org/x/crypto/hkdf"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
@ -24,18 +23,18 @@ type GateData struct {
AccessKey string AccessKey string
BearerToken *token.BearerToken BearerToken *token.BearerToken
SessionToken *session.Token SessionToken *session.Token
GateKey *ecdsa.PublicKey GateKey *keys.PublicKey
} }
// NewGateData returns GateData from provided bearer token and public gate key. // 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} return &GateData{GateKey: gateKey, BearerToken: bearerTkn}
} }
// Secrets represents AccessKey and key to encrypt gate tokens. // Secrets represents AccessKey and key to encrypt gate tokens.
type Secrets struct { type Secrets struct {
AccessKey string AccessKey string
EphemeralKey *ecdsa.PrivateKey EphemeralKey *keys.PrivateKey
} }
// Marshal returns the wire-format of AccessBox. // Marshal returns the wire-format of AccessBox.
@ -52,11 +51,11 @@ func (x *AccessBox) Unmarshal(data []byte) error {
// Session token can be nil. // Session token can be nil.
func PackTokens(gatesData []*GateData) (*AccessBox, *Secrets, error) { func PackTokens(gatesData []*GateData) (*AccessBox, *Secrets, error) {
box := &AccessBox{} box := &AccessBox{}
ephemeralKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) ephemeralKey, err := keys.NewPrivateKey()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
box.OwnerPublicKey = crypto.MarshalPublicKey(&ephemeralKey.PublicKey) box.OwnerPublicKey = ephemeralKey.PublicKey().Bytes()
secret, err := generateSecret() secret, err := generateSecret()
if err != nil { if err != nil {
@ -71,9 +70,12 @@ func PackTokens(gatesData []*GateData) (*AccessBox, *Secrets, error) {
} }
// GetTokens returns gate tokens from AccessBox. // GetTokens returns gate tokens from AccessBox.
func (x *AccessBox) GetTokens(owner *ecdsa.PrivateKey) (*GateData, error) { func (x *AccessBox) GetTokens(owner *keys.PrivateKey) (*GateData, error) {
sender := crypto.UnmarshalPublicKey(x.OwnerPublicKey) sender, err := keys.NewPublicKeyFromBytes(x.OwnerPublicKey, elliptic.P256())
ownerKey := crypto.MarshalPublicKey(&owner.PublicKey) if err != nil {
return nil, fmt.Errorf("couldn't unmarshal OwnerPublicKey: %w", err)
}
ownerKey := owner.PublicKey().Bytes()
for _, gate := range x.Gates { for _, gate := range x.Gates {
if !bytes.Equal(gate.GatePublicKey, ownerKey) { if !bytes.Equal(gate.GatePublicKey, ownerKey) {
continue 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) 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 { for i, gate := range gatesData {
encBearer, err := gate.BearerToken.Marshal() encBearer, err := gate.BearerToken.Marshal()
if err != nil { if err != nil {
@ -117,7 +119,7 @@ func (x *AccessBox) addTokens(gatesData []*GateData, ephemeralKey *ecdsa.Private
return nil 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) data, err := proto.Marshal(tokens)
if err != nil { if err != nil {
return nil, err return nil, err
@ -129,12 +131,12 @@ func encodeGate(ephemeralKey *ecdsa.PrivateKey, ownerKey *ecdsa.PublicKey, token
} }
gate := new(AccessBox_Gate) gate := new(AccessBox_Gate)
gate.GatePublicKey = crypto.MarshalPublicKey(ownerKey) gate.GatePublicKey = ownerKey.Bytes()
gate.Tokens = encrypted gate.Tokens = encrypted
return gate, nil 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) data, err := decrypt(owner, sender, gate.Tokens)
if err != nil { if err != nil {
return nil, err return nil, err
@ -153,14 +155,14 @@ func decodeGate(gate *AccessBox_Gate, owner *ecdsa.PrivateKey, sender *ecdsa.Pub
return nil, err return nil, err
} }
gateData := NewGateData(&owner.PublicKey, bearerTkn) gateData := NewGateData(owner.PublicKey(), bearerTkn)
gateData.SessionToken = sessionTkn gateData.SessionToken = sessionTkn
gateData.AccessKey = hex.EncodeToString(tokens.AccessKey) gateData.AccessKey = hex.EncodeToString(tokens.AccessKey)
return gateData, nil return gateData, nil
} }
func generateShared256(prv *ecdsa.PrivateKey, pub *ecdsa.PublicKey) (sk []byte, err error) { func generateShared256(prv *keys.PrivateKey, pub *keys.PublicKey) (sk []byte, err error) {
if prv.PublicKey.Curve != pub.Curve { if prv.PublicKey().Curve != pub.Curve {
return nil, fmt.Errorf("not equal curves") return nil, fmt.Errorf("not equal curves")
} }
@ -183,7 +185,7 @@ func deriveKey(secret []byte) ([]byte, error) {
return key, err 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) enc, err := getCipher(owner, sender)
if err != nil { if err != nil {
return nil, err 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 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) dec, err := getCipher(owner, sender)
if err != nil { if err != nil {
return nil, err 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) 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) secret, err := generateShared256(owner, sender)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -1,16 +1,13 @@
package accessbox package accessbox
import ( import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"testing" "testing"
"github.com/google/uuid" "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/acl/eacl"
"github.com/nspcc-dev/neofs-api-go/pkg/session" "github.com/nspcc-dev/neofs-api-go/pkg/session"
"github.com/nspcc-dev/neofs-api-go/pkg/token" "github.com/nspcc-dev/neofs-api-go/pkg/token"
crypto "github.com/nspcc-dev/neofs-crypto"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -19,22 +16,22 @@ func Test_tokens_encrypt_decrypt(t *testing.T) {
tkn = token.NewBearerToken() tkn = token.NewBearerToken()
tkn2 = token.NewBearerToken() tkn2 = token.NewBearerToken()
) )
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) cred, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable()) tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(&sec.PrivateKey))
rawTkn, err := tkn.Marshal() rawTkn, err := tkn.Marshal()
require.NoError(t, err) require.NoError(t, err)
data, err := encrypt(cred, &cred.PublicKey, rawTkn) data, err := encrypt(cred, cred.PublicKey(), rawTkn)
require.NoError(t, err) require.NoError(t, err)
rawTkn2, err := decrypt(cred, &cred.PublicKey, data) rawTkn2, err := decrypt(cred, cred.PublicKey(), data)
require.NoError(t, err) require.NoError(t, err)
err = tkn2.Unmarshal(rawTkn2) err = tkn2.Unmarshal(rawTkn2)
@ -50,16 +47,16 @@ func Test_bearer_token_in_access_box(t *testing.T) {
tkn = token.NewBearerToken() tkn = token.NewBearerToken()
) )
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) cred, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable()) 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}) box, _, err = PackTokens([]*GateData{gate})
require.NoError(t, err) require.NoError(t, err)
@ -82,10 +79,10 @@ func Test_session_token_in_access_box(t *testing.T) {
tkn = session.NewToken() tkn = session.NewToken()
) )
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) cred, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
tok := session.NewToken() tok := session.NewToken()
@ -93,10 +90,10 @@ func Test_session_token_in_access_box(t *testing.T) {
uid, err := uuid.New().MarshalBinary() uid, err := uuid.New().MarshalBinary()
require.NoError(t, err) require.NoError(t, err)
tok.SetID(uid) tok.SetID(uid)
tok.SetSessionKey(crypto.MarshalPublicKey(&sec.PublicKey)) tok.SetSessionKey(sec.PublicKey().Bytes())
require.NoError(t, tkn.Sign(sec)) require.NoError(t, tkn.Sign(&sec.PrivateKey))
gate := NewGateData(&cred.PublicKey, token.NewBearerToken()) gate := NewGateData(cred.PublicKey(), token.NewBearerToken())
gate.SessionToken = tkn gate.SessionToken = tkn
box, _, err = PackTokens([]*GateData{gate}) box, _, err = PackTokens([]*GateData{gate})
require.NoError(t, err) require.NoError(t, err)
@ -119,29 +116,29 @@ func Test_accessbox_multiple_keys(t *testing.T) {
tkn = token.NewBearerToken() tkn = token.NewBearerToken()
) )
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable()) tkn.SetEACLTable(eacl.NewTable())
require.NoError(t, tkn.SignToken(sec)) require.NoError(t, tkn.SignToken(&sec.PrivateKey))
count := 10 count := 10
gates := make([]*GateData, 0, count) gates := make([]*GateData, 0, count)
keys := make([]*ecdsa.PrivateKey, 0, count) privateKeys := make([]*keys.PrivateKey, 0, count)
{ // generate keys { // generate keys
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) cred, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
gates = append(gates, NewGateData(&cred.PublicKey, tkn)) gates = append(gates, NewGateData(cred.PublicKey(), tkn))
keys = append(keys, cred) privateKeys = append(privateKeys, cred)
} }
} }
box, _, err = PackTokens(gates) box, _, err = PackTokens(gates)
require.NoError(t, err) require.NoError(t, err)
for i, k := range keys { for i, k := range privateKeys {
tkns, err := box.GetTokens(k) tkns, err := box.GetTokens(k)
require.NoError(t, err, "key #%d: %s failed", i, k) require.NoError(t, err, "key #%d: %s failed", i, k)
require.Equal(t, tkns.BearerToken, tkn) require.Equal(t, tkns.BearerToken, tkn)
@ -154,19 +151,19 @@ func Test_unknown_key(t *testing.T) {
tkn = token.NewBearerToken() tkn = token.NewBearerToken()
) )
sec, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) sec, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
cred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) cred, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
wrongCred, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) wrongCred, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
tkn.SetEACLTable(eacl.NewTable()) 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}) box, _, err = PackTokens([]*GateData{gate})
require.NoError(t, err) require.NoError(t, err)

View file

@ -3,12 +3,12 @@ package tokens
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/ecdsa"
"errors" "errors"
"strconv" "strconv"
"sync" "sync"
"time" "time"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-api-go/pkg/client" "github.com/nspcc-dev/neofs-api-go/pkg/client"
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id" cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
"github.com/nspcc-dev/neofs-api-go/pkg/object" "github.com/nspcc-dev/neofs-api-go/pkg/object"
@ -21,11 +21,11 @@ type (
// Credentials is a bearer token get/put interface. // Credentials is a bearer token get/put interface.
Credentials interface { Credentials interface {
GetTokens(context.Context, *object.Address) (*accessbox.GateData, error) 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 { cred struct {
key *ecdsa.PrivateKey key *keys.PrivateKey
pool pool.Pool pool pool.Pool
} }
) )
@ -46,7 +46,7 @@ var bufferPool = sync.Pool{
var _ = New var _ = New
// New creates new Credentials instance using given cli and key. // 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} return &cred{pool: conns, key: key}
} }
@ -91,7 +91,7 @@ func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*acce
return &box, nil 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 ( var (
err error err error
created = strconv.FormatInt(time.Now().Unix(), 10) created = strconv.FormatInt(time.Now().Unix(), 10)

1
go.mod
View file

@ -9,7 +9,6 @@ require (
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/nspcc-dev/neo-go v0.95.3 github.com/nspcc-dev/neo-go v0.95.3
github.com/nspcc-dev/neofs-api-go v1.27.1 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-node v1.22.0
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20210624072335-0348eb331c92 github.com/nspcc-dev/neofs-sdk-go v0.0.0-20210624072335-0348eb331c92
github.com/prometheus/client_golang v1.9.0 github.com/prometheus/client_golang v1.9.0

61
internal/wallet/wallet.go Normal file
View 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
}