2019-03-18 10:55:06 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package trust
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
2019-04-12 15:28:27 +01:00
|
|
|
"github.com/zeebo/errs"
|
2019-06-04 13:31:39 +01:00
|
|
|
monkit "gopkg.in/spacemonkeygo/monkit.v2"
|
2019-04-12 15:28:27 +01:00
|
|
|
|
2019-03-18 10:55:06 +00:00
|
|
|
"storj.io/storj/pkg/auth/signing"
|
|
|
|
"storj.io/storj/pkg/identity"
|
|
|
|
"storj.io/storj/pkg/kademlia"
|
|
|
|
"storj.io/storj/pkg/storj"
|
|
|
|
)
|
|
|
|
|
2019-04-12 15:28:27 +01:00
|
|
|
// Error is the default error class
|
|
|
|
var Error = errs.Class("trust:")
|
2019-06-04 13:31:39 +01:00
|
|
|
var mon = monkit.Package()
|
2019-04-12 15:28:27 +01:00
|
|
|
|
2019-03-18 10:55:06 +00:00
|
|
|
// Pool implements different peer verifications.
|
|
|
|
type Pool struct {
|
|
|
|
kademlia *kademlia.Kademlia
|
|
|
|
|
|
|
|
mu sync.RWMutex
|
|
|
|
|
|
|
|
trustAllSatellites bool
|
|
|
|
trustedSatellites map[storj.NodeID]*satelliteInfoCache
|
|
|
|
}
|
|
|
|
|
|
|
|
// satelliteInfoCache caches identity information about a satellite
|
|
|
|
type satelliteInfoCache struct {
|
2019-04-24 09:13:48 +01:00
|
|
|
mu sync.Mutex
|
2019-03-18 10:55:06 +00:00
|
|
|
identity *identity.PeerIdentity
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewPool creates a new trust pool using kademlia to find certificates and with the specified list of trusted satellites.
|
|
|
|
func NewPool(kademlia *kademlia.Kademlia, trustAll bool, trustedSatelliteIDs string) (*Pool, error) {
|
|
|
|
if trustAll {
|
|
|
|
return &Pool{
|
|
|
|
kademlia: kademlia,
|
|
|
|
|
|
|
|
trustAllSatellites: true,
|
|
|
|
trustedSatellites: map[storj.NodeID]*satelliteInfoCache{},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: preload all satellite peer identities
|
|
|
|
|
|
|
|
// parse the comma separated list of approved satellite IDs into an array of storj.NodeIDs
|
|
|
|
trusted := make(map[storj.NodeID]*satelliteInfoCache)
|
|
|
|
|
|
|
|
for _, s := range strings.Split(trustedSatelliteIDs, ",") {
|
2019-05-21 12:48:47 +01:00
|
|
|
s = strings.TrimSpace(s)
|
2019-03-18 10:55:06 +00:00
|
|
|
if s == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
satelliteID, err := storj.NodeIDFromString(s)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
trusted[satelliteID] = &satelliteInfoCache{} // we will set these later
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Pool{
|
|
|
|
kademlia: kademlia,
|
|
|
|
|
|
|
|
trustAllSatellites: false,
|
|
|
|
trustedSatellites: trusted,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// VerifySatelliteID checks whether id corresponds to a trusted satellite.
|
2019-06-04 13:31:39 +01:00
|
|
|
func (pool *Pool) VerifySatelliteID(ctx context.Context, id storj.NodeID) (err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
2019-03-18 10:55:06 +00:00
|
|
|
if pool.trustAllSatellites {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
pool.mu.RLock()
|
|
|
|
defer pool.mu.RUnlock()
|
|
|
|
|
|
|
|
_, ok := pool.trustedSatellites[id]
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("satellite %q is untrusted", id)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// VerifyUplinkID verifides whether id corresponds to a trusted uplink.
|
2019-06-04 13:31:39 +01:00
|
|
|
func (pool *Pool) VerifyUplinkID(ctx context.Context, id storj.NodeID) (err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
2019-03-18 10:55:06 +00:00
|
|
|
// trusting all the uplinks for now
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSignee gets the corresponding signee for verifying signatures.
|
2019-04-08 21:31:20 +01:00
|
|
|
// It ignores passed in ctx cancellation to avoid miscaching between concurrent requests.
|
2019-06-04 13:31:39 +01:00
|
|
|
func (pool *Pool) GetSignee(ctx context.Context, id storj.NodeID) (_ signing.Signee, err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
2019-03-18 10:55:06 +00:00
|
|
|
// lookup peer identity with id
|
|
|
|
pool.mu.RLock()
|
|
|
|
info, ok := pool.trustedSatellites[id]
|
|
|
|
pool.mu.RUnlock()
|
|
|
|
|
|
|
|
if pool.trustAllSatellites {
|
|
|
|
// add a new entry
|
|
|
|
if !ok {
|
|
|
|
pool.mu.Lock()
|
|
|
|
// did another goroutine manage to make it first?
|
|
|
|
info, ok = pool.trustedSatellites[id]
|
|
|
|
if !ok {
|
|
|
|
info = &satelliteInfoCache{}
|
|
|
|
pool.trustedSatellites[id] = info
|
|
|
|
}
|
|
|
|
pool.mu.Unlock()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("signee %q is untrusted", id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-24 09:13:48 +01:00
|
|
|
info.mu.Lock()
|
|
|
|
defer info.mu.Unlock()
|
2019-04-12 15:28:27 +01:00
|
|
|
|
2019-04-24 09:13:48 +01:00
|
|
|
if info.identity == nil {
|
|
|
|
identity, err := pool.kademlia.FetchPeerIdentity(ctx, id)
|
|
|
|
if err != nil {
|
|
|
|
if err == context.Canceled {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return nil, Error.Wrap(err)
|
|
|
|
}
|
2019-04-12 15:28:27 +01:00
|
|
|
info.identity = identity
|
2019-04-24 09:13:48 +01:00
|
|
|
}
|
2019-03-18 10:55:06 +00:00
|
|
|
|
|
|
|
return signing.SigneeFromPeerIdentity(info.identity), nil
|
|
|
|
}
|