storageode/apikey: added service, CLI issue api key
Change-Id: I840cd0fdbd8dca884eefbd111f21fd3990c11e68
This commit is contained in:
parent
2b59640f18
commit
a17cd9aa3e
@ -24,6 +24,7 @@ import (
|
||||
"storj.io/storj/pkg/revocation"
|
||||
_ "storj.io/storj/private/version" // This attaches version information during release builds.
|
||||
"storj.io/storj/storagenode"
|
||||
"storj.io/storj/storagenode/apikeys"
|
||||
"storj.io/storj/storagenode/storagenodedb"
|
||||
)
|
||||
|
||||
@ -85,6 +86,11 @@ var (
|
||||
RunE: cmdGracefulExitStatus,
|
||||
Annotations: map[string]string{"type": "helper"},
|
||||
}
|
||||
issueAPITokenCmd = &cobra.Command{
|
||||
Use: "issue-apikey",
|
||||
Short: "Issue apikey for mnd",
|
||||
RunE: cmdIssue,
|
||||
}
|
||||
|
||||
runCfg StorageNodeFlags
|
||||
setupCfg StorageNodeFlags
|
||||
@ -119,6 +125,7 @@ func init() {
|
||||
rootCmd.AddCommand(dashboardCmd)
|
||||
rootCmd.AddCommand(gracefulExitInitCmd)
|
||||
rootCmd.AddCommand(gracefulExitStatusCmd)
|
||||
rootCmd.AddCommand(issueAPITokenCmd)
|
||||
process.Bind(runCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(setupCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir), cfgstruct.SetupMode())
|
||||
process.Bind(configCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir), cfgstruct.SetupMode())
|
||||
@ -126,6 +133,7 @@ func init() {
|
||||
process.Bind(dashboardCmd, &dashboardCfg, defaults, cfgstruct.ConfDir(defaultDiagDir))
|
||||
process.Bind(gracefulExitInitCmd, &diagCfg, defaults, cfgstruct.ConfDir(defaultDiagDir))
|
||||
process.Bind(gracefulExitStatusCmd, &diagCfg, defaults, cfgstruct.ConfDir(defaultDiagDir))
|
||||
process.Bind(issueAPITokenCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
}
|
||||
|
||||
func cmdRun(cmd *cobra.Command, args []string) (err error) {
|
||||
@ -286,6 +294,36 @@ func cmdConfig(cmd *cobra.Command, args []string) (err error) {
|
||||
return fpath.EditFile(conf)
|
||||
}
|
||||
|
||||
func cmdIssue(cmd *cobra.Command, args []string) (err error) {
|
||||
ctx, _ := process.Ctx(cmd)
|
||||
|
||||
ident, err := runCfg.Identity.Load()
|
||||
if err != nil {
|
||||
zap.L().Fatal("Failed to load identity.", zap.Error(err))
|
||||
} else {
|
||||
zap.L().Info("Identity loaded.", zap.Stringer("Node ID", ident.ID))
|
||||
}
|
||||
|
||||
db, err := storagenodedb.OpenExisting(ctx, zap.L().Named("db"), diagCfg.DatabaseConfig())
|
||||
if err != nil {
|
||||
return errs.New("Error starting master database on storage node: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
err = errs.Combine(err, db.Close())
|
||||
}()
|
||||
|
||||
service := apikeys.NewService(db.Secret())
|
||||
|
||||
apiKey, err := service.Issue(ctx)
|
||||
if err != nil {
|
||||
return errs.New("Error while trying to issue new api key: %v", err)
|
||||
}
|
||||
|
||||
fmt.Print(apiKey.Secret.String())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func cmdDiag(cmd *cobra.Command, args []string) (err error) {
|
||||
ctx, _ := process.Ctx(cmd)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package apikey
|
||||
package apikeys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -41,8 +41,8 @@ type APIKey struct {
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
// NewSecretToken creates new apikey token.
|
||||
func NewSecretToken() (Secret, error) {
|
||||
// NewSecret creates new apikey secret.
|
||||
func NewSecret() (Secret, error) {
|
||||
var b [32]byte
|
||||
|
||||
_, err := rand.Read(b[:])
|
@ -1,7 +1,7 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package apikey_test
|
||||
package apikeys_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@ -11,20 +11,20 @@ import (
|
||||
|
||||
"storj.io/common/testcontext"
|
||||
"storj.io/storj/storagenode"
|
||||
"storj.io/storj/storagenode/apikey"
|
||||
"storj.io/storj/storagenode/apikeys"
|
||||
"storj.io/storj/storagenode/storagenodedb/storagenodedbtest"
|
||||
)
|
||||
|
||||
func TestSecretDB(t *testing.T) {
|
||||
storagenodedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db storagenode.DB) {
|
||||
secrets := db.Secret()
|
||||
token, err := apikey.NewSecretToken()
|
||||
token, err := apikeys.NewSecret()
|
||||
assert.NoError(t, err)
|
||||
token2, err := apikey.NewSecretToken()
|
||||
token2, err := apikeys.NewSecret()
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Run("Test StoreSecret", func(t *testing.T) {
|
||||
err := secrets.Store(ctx, apikey.APIKey{
|
||||
err := secrets.Store(ctx, apikeys.APIKey{
|
||||
Secret: token,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
})
|
64
storagenode/apikeys/service.go
Normal file
64
storagenode/apikeys/service.go
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package apikeys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/spacemonkeygo/monkit/v3"
|
||||
"github.com/zeebo/errs"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrService defines secret service error.
|
||||
ErrService = errs.Class("secret service error")
|
||||
|
||||
mon = monkit.Package()
|
||||
)
|
||||
|
||||
// Service responsible for operations with storagenode's uniq secret.
|
||||
//
|
||||
// architecture: Service
|
||||
type Service struct {
|
||||
store DB
|
||||
}
|
||||
|
||||
// NewService is a constructor for service.
|
||||
func NewService(db DB) *Service {
|
||||
return &Service{store: db}
|
||||
}
|
||||
|
||||
// Issue generates new api key and stores it into db.
|
||||
func (service *Service) Issue(ctx context.Context) (apiKey APIKey, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
secret, err := NewSecret()
|
||||
if err != nil {
|
||||
return APIKey{}, ErrService.Wrap(err)
|
||||
}
|
||||
|
||||
apiKey.Secret = secret
|
||||
apiKey.CreatedAt = time.Now()
|
||||
|
||||
err = service.store.Store(ctx, apiKey)
|
||||
if err != nil {
|
||||
return APIKey{}, ErrService.Wrap(err)
|
||||
}
|
||||
|
||||
return apiKey, nil
|
||||
}
|
||||
|
||||
// Check returns error if api key does not exists.
|
||||
func (service *Service) Check(ctx context.Context, secret Secret) (err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
return service.store.Check(ctx, secret)
|
||||
}
|
||||
|
||||
// Remove revokes apikey, deletes it from db.
|
||||
func (service *Service) Remove(ctx context.Context, secret Secret) (err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
return ErrService.Wrap(service.store.Revoke(ctx, secret))
|
||||
}
|
@ -31,7 +31,7 @@ import (
|
||||
"storj.io/storj/private/version/checker"
|
||||
"storj.io/storj/storage"
|
||||
"storj.io/storj/storage/filestore"
|
||||
"storj.io/storj/storagenode/apikey"
|
||||
"storj.io/storj/storagenode/apikeys"
|
||||
"storj.io/storj/storagenode/bandwidth"
|
||||
"storj.io/storj/storagenode/collector"
|
||||
"storj.io/storj/storagenode/console"
|
||||
@ -88,7 +88,7 @@ type DB interface {
|
||||
Notifications() notifications.DB
|
||||
Payout() payout.DB
|
||||
Pricing() pricing.DB
|
||||
Secret() apikey.DB
|
||||
Secret() apikeys.DB
|
||||
|
||||
Preflight(ctx context.Context) error
|
||||
}
|
||||
|
@ -10,11 +10,11 @@ import (
|
||||
|
||||
"github.com/zeebo/errs"
|
||||
|
||||
"storj.io/storj/storagenode/apikey"
|
||||
"storj.io/storj/storagenode/apikeys"
|
||||
)
|
||||
|
||||
// ensures that secretDB implements apikey.DB interface.
|
||||
var _ apikey.DB = (*secretDB)(nil)
|
||||
// ensures that secretDB implements apikeys.DB interface.
|
||||
var _ apikeys.DB = (*secretDB)(nil)
|
||||
|
||||
// ErrSecret represents errors from the apikey database.
|
||||
var ErrSecret = errs.Class("apikey db error")
|
||||
@ -28,7 +28,7 @@ type secretDB struct {
|
||||
}
|
||||
|
||||
// Store stores apikey into database.
|
||||
func (db *secretDB) Store(ctx context.Context, secret apikey.APIKey) (err error) {
|
||||
func (db *secretDB) Store(ctx context.Context, secret apikeys.APIKey) (err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
query := `INSERT INTO secret (
|
||||
@ -45,7 +45,7 @@ func (db *secretDB) Store(ctx context.Context, secret apikey.APIKey) (err error)
|
||||
}
|
||||
|
||||
// Check checks if apikey exists in db by token.
|
||||
func (db *secretDB) Check(ctx context.Context, token apikey.Secret) (err error) {
|
||||
func (db *secretDB) Check(ctx context.Context, token apikeys.Secret) (err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
var bytes []uint8
|
||||
@ -62,7 +62,7 @@ func (db *secretDB) Check(ctx context.Context, token apikey.Secret) (err error)
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return apikey.ErrNoSecret.Wrap(err)
|
||||
return apikeys.ErrNoSecret.Wrap(err)
|
||||
}
|
||||
return ErrSecret.Wrap(err)
|
||||
}
|
||||
@ -71,7 +71,7 @@ func (db *secretDB) Check(ctx context.Context, token apikey.Secret) (err error)
|
||||
}
|
||||
|
||||
// Revoke removes apikey from db.
|
||||
func (db *secretDB) Revoke(ctx context.Context, secret apikey.Secret) (err error) {
|
||||
func (db *secretDB) Revoke(ctx context.Context, secret apikeys.Secret) (err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
query := `DELETE FROM secret WHERE token = ?`
|
||||
|
@ -25,7 +25,7 @@ import (
|
||||
"storj.io/storj/private/tagsql"
|
||||
"storj.io/storj/storage"
|
||||
"storj.io/storj/storage/filestore"
|
||||
"storj.io/storj/storagenode/apikey"
|
||||
"storj.io/storj/storagenode/apikeys"
|
||||
"storj.io/storj/storagenode/bandwidth"
|
||||
"storj.io/storj/storagenode/notifications"
|
||||
"storj.io/storj/storagenode/orders"
|
||||
@ -544,7 +544,7 @@ func (db *DB) Pricing() pricing.DB {
|
||||
}
|
||||
|
||||
// Secret returns instance of the Secret database.
|
||||
func (db *DB) Secret() apikey.DB {
|
||||
func (db *DB) Secret() apikeys.DB {
|
||||
return db.secretDB
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user