lnd.xprv/macaroons/store.go
Alex 21c29c33d7 multi: upgrade macaroons to v2, replace per-method auth with interceptors
This commit reworks the macaroon authentication framework to use the
v2 macaroon format and bakery API. It also replaces the code in each
RPC method which calls the macaroon verifier with interceptors which
call the macaroon verifier instead. In addition, the operation
permissions are reworked to fit the new format of "allow" commands
(specifically, entity/operation permissions instead of method
permissions).
2018-01-31 17:14:49 -08:00

102 lines
2.4 KiB
Go

package macaroons
import (
"crypto/rand"
"fmt"
"io"
"golang.org/x/net/context"
"github.com/boltdb/bolt"
)
const (
// RootKeyLen is the length of a root key.
RootKeyLen = 32
)
var (
// rootKeyBucketName is the name of the root key store bucket.
rootKeyBucketName = []byte("macrootkeys")
// defaultRootKeyID is the ID of the default root key. The first is
// just 0, to emulate the memory storage that comes with bakery.
//
// TODO(aakselrod): Add support for key rotation.
defaultRootKeyID = []byte("0")
// macaroonBucketName is the name of the macaroon store bucket.
macaroonBucketName = []byte("macaroons")
)
// RootKeyStorage implements the bakery.RootKeyStorage interface.
type RootKeyStorage struct {
*bolt.DB
}
// NewRootKeyStorage creates a RootKeyStorage instance.
// TODO(aakselrod): Add support for encryption of data with passphrase.
func NewRootKeyStorage(db *bolt.DB) (*RootKeyStorage, error) {
// If the store's bucket doesn't exist, create it.
err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(rootKeyBucketName)
return err
})
if err != nil {
return nil, err
}
// Return the DB wrapped in a RootKeyStorage object.
return &RootKeyStorage{db}, nil
}
// Get implements the Get method for the bakery.RootKeyStorage interface.
func (r *RootKeyStorage) Get(_ context.Context, id []byte) ([]byte, error) {
var rootKey []byte
err := r.View(func(tx *bolt.Tx) error {
dbKey := tx.Bucket(rootKeyBucketName).Get(id)
if len(dbKey) == 0 {
return fmt.Errorf("root key with id %s doesn't exist",
string(id))
}
rootKey = make([]byte, len(dbKey))
copy(rootKey[:], dbKey)
return nil
})
if err != nil {
return nil, err
}
return rootKey, nil
}
// RootKey implements the RootKey method for the bakery.RootKeyStorage
// interface.
// TODO(aakselrod): Add support for key rotation.
func (r *RootKeyStorage) RootKey(_ context.Context) ([]byte, []byte, error) {
var rootKey []byte
id := defaultRootKeyID
err := r.Update(func(tx *bolt.Tx) error {
ns := tx.Bucket(rootKeyBucketName)
rootKey = ns.Get(id)
// If there's no root key stored in the bucket yet, create one.
if len(rootKey) != 0 {
return nil
}
// Create a RootKeyLen-byte root key.
rootKey = make([]byte, RootKeyLen)
if _, err := io.ReadFull(rand.Reader, rootKey[:]); err != nil {
return err
}
return ns.Put(id, rootKey)
})
if err != nil {
return nil, nil, err
}
return rootKey, id, nil
}