ea1408f7a8
As a reminder: latest clingy removed the requirement of having custom context (which made the usage of context.WithValue harder) and uses simple context instead. Clingy saves the stdin/stdout/stderr to the context (earlier to separated context type) to make it available for unit testing. Change-Id: I8896574f4670721de43a577cd4b35952e3b5d00e
142 lines
3.6 KiB
Go
142 lines
3.6 KiB
Go
// Copyright (C) 2021 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/zeebo/clingy"
|
|
"github.com/zeebo/errs"
|
|
|
|
"storj.io/common/base58"
|
|
"storj.io/common/macaroon"
|
|
"storj.io/common/pb"
|
|
"storj.io/storj/cmd/uplink/ulext"
|
|
)
|
|
|
|
// ensures that cmdAccessInspect implements clingy.Command.
|
|
var _ clingy.Command = (*cmdAccessInspect)(nil)
|
|
|
|
// cmdAccessInspect is an access inspect command itself.
|
|
type cmdAccessInspect struct {
|
|
ex ulext.External
|
|
access *string
|
|
}
|
|
|
|
// newCmdAccessInspect is a constructor for cmdAccessInspect.
|
|
func newCmdAccessInspect(ex ulext.External) clingy.Command {
|
|
return &cmdAccessInspect{ex: ex}
|
|
}
|
|
|
|
// Setup is called to define and parse arguments.
|
|
func (c *cmdAccessInspect) Setup(params clingy.Parameters) {
|
|
c.access = params.Arg("access", "Inspect access by its name or value.", clingy.Optional).(*string)
|
|
}
|
|
|
|
// Execute runs the command.
|
|
func (c *cmdAccessInspect) Execute(ctx context.Context) error {
|
|
toOpen := ""
|
|
if c.access != nil {
|
|
toOpen = *c.access
|
|
}
|
|
|
|
access, err := c.ex.OpenAccess(toOpen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
serializedAccess, err := access.Serialize()
|
|
if err != nil {
|
|
return errs.New("could not serialize access: %+v", err)
|
|
}
|
|
|
|
p, err := parseAccessRaw(serializedAccess)
|
|
if err != nil {
|
|
return errs.New("could not parse access: %+v", err)
|
|
}
|
|
|
|
m, err := macaroon.ParseMacaroon(p.ApiKey)
|
|
if err != nil {
|
|
return errs.New("could not parse macaroon: %+v", err)
|
|
}
|
|
|
|
// TODO: this could be better
|
|
apiKey, err := macaroon.ParseRawAPIKey(p.ApiKey)
|
|
if err != nil {
|
|
return errs.New("could not parse api key: %+v", err)
|
|
}
|
|
|
|
accessInspect := accessInspect{
|
|
SatelliteAddr: p.SatelliteAddr,
|
|
EncryptionAccess: p.EncryptionAccess,
|
|
APIKey: apiKey.Serialize(),
|
|
Macaroon: accessInspectMacaroon{
|
|
Head: m.Head(),
|
|
Caveats: []macaroon.Caveat{},
|
|
Tail: m.Tail(),
|
|
},
|
|
}
|
|
|
|
for _, cb := range m.Caveats() {
|
|
var c macaroon.Caveat
|
|
|
|
err = pb.Unmarshal(cb, &c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
accessInspect.Macaroon.Caveats = append(accessInspect.Macaroon.Caveats, c)
|
|
}
|
|
|
|
bs, err := json.MarshalIndent(accessInspect, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Fprintln(clingy.Stdout(ctx), string(bs))
|
|
|
|
return nil
|
|
}
|
|
|
|
// parseAccessRaw decodes Scope from base58 string, that contains SatelliteAddress, ApiKey, and EncryptionAccess.
|
|
func parseAccessRaw(access string) (_ *pb.Scope, err error) {
|
|
data, version, err := base58.CheckDecode(access)
|
|
if err != nil || version != 0 {
|
|
return nil, errs.New("invalid access grant format: %w", err)
|
|
}
|
|
|
|
p := new(pb.Scope)
|
|
if err := pb.Unmarshal(data, p); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return p, nil
|
|
}
|
|
|
|
// accessInspect contains all info about access inspection that should be presented on cli.
|
|
type accessInspect struct {
|
|
SatelliteAddr string `json:"satellite_addr"`
|
|
EncryptionAccess *pb.EncryptionAccess `json:"encryption_access"`
|
|
APIKey string `json:"api_key"`
|
|
Macaroon accessInspectMacaroon `json:"macaroon"`
|
|
}
|
|
|
|
// base64url stores bytes representation of base64 encoded url.
|
|
type base64url []byte
|
|
|
|
// MarshalJSON implements the json.Marshaler interface for base64url.
|
|
func (b base64url) MarshalJSON() ([]byte, error) {
|
|
return []byte(`"` + base64.URLEncoding.EncodeToString(b) + `"`), nil
|
|
}
|
|
|
|
// accessInspectMacaroon contains all info about access macaroon that should be presented on cli.
|
|
type accessInspectMacaroon struct {
|
|
Head base64url `json:"head"`
|
|
Caveats []macaroon.Caveat `json:"caveats"`
|
|
Tail base64url `json:"tail"`
|
|
}
|