api: Support /ws/ and /dns/ multiaddresses parsing. Log all errors

The multiaddresses protocols for websockets and dns are only registered
with init() function when loading the modules. ipfs-cluster-ctl
uses just the api, which did not load these modules so converting
from serialized types caused bad panics.

We have also ignored errors in the api library under the thinking that it
would only parse things serialized by us, but this has made parsing errors
to go unnoticed. From now, all errors are logged and some precautions
are taking to better handle the possibility of nil objects.

License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
This commit is contained in:
Hector Sanjuan 2017-12-07 23:59:24 +01:00
parent 72928d5e3b
commit 6a243df4da
6 changed files with 114 additions and 41 deletions

View File

@ -12,11 +12,19 @@ import (
"time"
cid "github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log"
peer "github.com/libp2p/go-libp2p-peer"
protocol "github.com/libp2p/go-libp2p-protocol"
ma "github.com/multiformats/go-multiaddr"
// needed to parse /ws multiaddresses
_ "github.com/libp2p/go-ws-transport"
// needed to prase /dns* multiaddresses
_ "github.com/multiformats/go-multiaddr-dns"
)
var logger = logging.Logger("apitypes")
// TrackerStatus values
const (
// IPFSStatus should never take this value
@ -121,7 +129,9 @@ type GlobalPinInfoSerial struct {
// ToSerial converts a GlobalPinInfo to its serializable version.
func (gpi GlobalPinInfo) ToSerial() GlobalPinInfoSerial {
s := GlobalPinInfoSerial{}
s.Cid = gpi.Cid.String()
if gpi.Cid != nil {
s.Cid = gpi.Cid.String()
}
s.PeerMap = make(map[string]PinInfoSerial)
for k, v := range gpi.PeerMap {
s.PeerMap[peer.IDB58Encode(k)] = v.ToSerial()
@ -131,13 +141,19 @@ func (gpi GlobalPinInfo) ToSerial() GlobalPinInfoSerial {
// ToGlobalPinInfo converts a GlobalPinInfoSerial to its native version.
func (gpis GlobalPinInfoSerial) ToGlobalPinInfo() GlobalPinInfo {
c, _ := cid.Decode(gpis.Cid)
c, err := cid.Decode(gpis.Cid)
if err != nil {
logger.Error(gpis.Cid, err)
}
gpi := GlobalPinInfo{
Cid: c,
PeerMap: make(map[peer.ID]PinInfo),
}
for k, v := range gpis.PeerMap {
p, _ := peer.IDB58Decode(k)
p, err := peer.IDB58Decode(k)
if err != nil {
logger.Error(k, err)
}
gpi.PeerMap[p] = v.ToPinInfo()
}
return gpi
@ -164,9 +180,18 @@ type PinInfoSerial struct {
// ToSerial converts a PinInfo to its serializable version.
func (pi PinInfo) ToSerial() PinInfoSerial {
c := ""
if pi.Cid != nil {
c = pi.Cid.String()
}
p := ""
if pi.Peer != "" {
p = peer.IDB58Encode(pi.Peer)
}
return PinInfoSerial{
Cid: pi.Cid.String(),
Peer: peer.IDB58Encode(pi.Peer),
Cid: c,
Peer: p,
Status: pi.Status.String(),
TS: pi.TS.UTC().Format(time.RFC3339),
Error: pi.Error,
@ -175,9 +200,18 @@ func (pi PinInfo) ToSerial() PinInfoSerial {
// ToPinInfo converts a PinInfoSerial to its native version.
func (pis PinInfoSerial) ToPinInfo() PinInfo {
c, _ := cid.Decode(pis.Cid)
p, _ := peer.IDB58Decode(pis.Peer)
ts, _ := time.Parse(time.RFC3339, pis.TS)
c, err := cid.Decode(pis.Cid)
if err != nil {
logger.Error(pis.Cid, err)
}
p, err := peer.IDB58Decode(pis.Peer)
if err != nil {
logger.Error(pis.Peer, err)
}
ts, err := time.Parse(time.RFC3339, pis.TS)
if err != nil {
logger.Error(pis.TS, err)
}
return PinInfo{
Cid: c,
Peer: p,
@ -208,8 +242,13 @@ type IPFSIDSerial struct {
// ToSerial converts IPFSID to a go serializable object
func (id *IPFSID) ToSerial() IPFSIDSerial {
p := ""
if id.ID != "" {
p = peer.IDB58Encode(id.ID)
}
return IPFSIDSerial{
ID: peer.IDB58Encode(id.ID),
ID: p,
Addresses: MultiaddrsToSerial(id.Addresses),
Error: id.Error,
}
@ -263,16 +302,15 @@ func (id ID) ToSerial() IDSerial {
// pkey, _ = id.PublicKey.Bytes()
//}
peers := make([]string, len(id.ClusterPeers), len(id.ClusterPeers))
for i, p := range id.ClusterPeers {
peers[i] = peer.IDB58Encode(p)
p := ""
if id.ID != "" {
p = peer.IDB58Encode(id.ID)
}
return IDSerial{
ID: peer.IDB58Encode(id.ID),
//PublicKey: pkey,
ID: p,
Addresses: MultiaddrsToSerial(id.Addresses),
ClusterPeers: peers,
ClusterPeers: PeersToStrings(id.ClusterPeers),
ClusterPeersAddresses: MultiaddrsToSerial(id.ClusterPeersAddresses),
Version: id.Version,
Commit: id.Commit,
@ -280,6 +318,7 @@ func (id ID) ToSerial() IDSerial {
Error: id.Error,
IPFS: id.IPFS.ToSerial(),
Peername: id.Peername,
//PublicKey: pkey,
}
}
@ -287,20 +326,18 @@ func (id ID) ToSerial() IDSerial {
// It will ignore any errors when parsing the fields.
func (ids IDSerial) ToID() ID {
id := ID{}
p, _ := peer.IDB58Decode(ids.ID)
p, err := peer.IDB58Decode(ids.ID)
if err != nil {
logger.Error(ids.ID, err)
}
id.ID = p
//if pkey, err := crypto.UnmarshalPublicKey(ids.PublicKey); err == nil {
// id.PublicKey = pkey
//}
peers := make([]peer.ID, len(ids.ClusterPeers), len(ids.ClusterPeers))
for i, p := range ids.ClusterPeers {
peers[i], _ = peer.IDB58Decode(p)
}
id.Addresses = ids.Addresses.ToMultiaddrs()
id.ClusterPeers = peers
id.ClusterPeers = StringsToPeers(ids.ClusterPeers)
id.ClusterPeersAddresses = ids.ClusterPeersAddresses.ToMultiaddrs()
id.Version = ids.Version
id.Commit = ids.Commit
@ -319,13 +356,20 @@ type MultiaddrsSerial []MultiaddrSerial
// MultiaddrToSerial converts a Multiaddress to its serializable form
func MultiaddrToSerial(addr ma.Multiaddr) MultiaddrSerial {
return MultiaddrSerial(addr.String())
if addr != nil {
return MultiaddrSerial(addr.String())
}
return ""
}
// ToMultiaddr converts a serializable Multiaddress to its original type.
// All errors are ignored.
func (addrS MultiaddrSerial) ToMultiaddr() ma.Multiaddr {
a, _ := ma.NewMultiaddr(string(addrS))
str := string(addrS)
a, err := ma.NewMultiaddr(str)
if err != nil {
logger.Error(str, err)
}
return a
}
@ -334,7 +378,9 @@ func (addrS MultiaddrSerial) ToMultiaddr() ma.Multiaddr {
func MultiaddrsToSerial(addrs []ma.Multiaddr) MultiaddrsSerial {
addrsS := make([]MultiaddrSerial, len(addrs), len(addrs))
for i, a := range addrs {
addrsS[i] = MultiaddrToSerial(a)
if a != nil {
addrsS[i] = MultiaddrToSerial(a)
}
}
return addrsS
}
@ -348,6 +394,30 @@ func (addrsS MultiaddrsSerial) ToMultiaddrs() []ma.Multiaddr {
return addrs
}
// PeersToStrings IDB58Encodes a list of peers.
func PeersToStrings(peers []peer.ID) []string {
strs := make([]string, len(peers))
for i, p := range peers {
if p != "" {
strs[i] = peer.IDB58Encode(p)
}
}
return strs
}
// StringsToPeers decodes peer.IDs from strings.
func StringsToPeers(strs []string) []peer.ID {
peers := make([]peer.ID, len(strs))
for i, p := range strs {
var err error
peers[i], err = peer.IDB58Decode(p)
if err != nil {
logger.Error(p, err)
}
}
return peers
}
// Pin is an argument that carries a Cid. It may carry more things in the
// future.
type Pin struct {
@ -375,27 +445,24 @@ type PinSerial struct {
// ToSerial converts a Pin to PinSerial.
func (pin Pin) ToSerial() PinSerial {
lenAllocs := len(pin.Allocations)
allocs := make([]string, lenAllocs, lenAllocs)
for i, p := range pin.Allocations {
allocs[i] = peer.IDB58Encode(p)
c := ""
if pin.Cid != nil {
c = pin.Cid.String()
}
return PinSerial{
Cid: pin.Cid.String(),
Cid: c,
Name: pin.Name,
Allocations: allocs,
Allocations: PeersToStrings(pin.Allocations),
ReplicationFactor: pin.ReplicationFactor,
}
}
// ToPin converts a PinSerial to its native form.
func (pins PinSerial) ToPin() Pin {
c, _ := cid.Decode(pins.Cid)
lenAllocs := len(pins.Allocations)
allocs := make([]peer.ID, lenAllocs, lenAllocs)
for i, p := range pins.Allocations {
allocs[i], _ = peer.IDB58Decode(p)
c, err := cid.Decode(pins.Cid)
if err != nil {
logger.Error(pins.Cid, err)
}
// legacy format management
@ -406,7 +473,7 @@ func (pins PinSerial) ToPin() Pin {
return Pin{
Cid: c,
Name: pins.Name,
Allocations: allocs,
Allocations: StringsToPeers(pins.Allocations),
ReplicationFactor: pins.ReplicationFactor,
}
}

View File

@ -11,6 +11,8 @@ import (
var testTime = time.Date(2017, 12, 31, 15, 45, 50, 0, time.UTC)
var testMAddr, _ = ma.NewMultiaddr("/ip4/1.2.3.4")
var testMAddr2, _ = ma.NewMultiaddr("/dns4/a.b.c.d")
var testMAddr3, _ = ma.NewMultiaddr("/ip4/127.0.0.1/tcp/8081/ws/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd")
var testCid1, _ = cid.Decode("QmP63DkAFEnDYNjDYBpyNDfttu1fvUw99x1brscPzpqmmq")
var testPeerID1, _ = peer.IDB58Decode("QmXZrtE5jQwXNqCJMfHUTQkvhQ4ZAnqMnmzFMJfLewuabc")
var testPeerID2, _ = peer.IDB58Decode("QmXZrtE5jQwXNqCJMfHUTQkvhQ4ZAnqMnmzFMJfLewuabd")
@ -76,14 +78,14 @@ func TestIDConv(t *testing.T) {
ID: testPeerID1,
Addresses: []ma.Multiaddr{testMAddr},
ClusterPeers: []peer.ID{testPeerID2},
ClusterPeersAddresses: []ma.Multiaddr{testMAddr},
ClusterPeersAddresses: []ma.Multiaddr{testMAddr2},
Version: "testv",
Commit: "ab",
RPCProtocolVersion: "testp",
Error: "teste",
IPFS: IPFSID{
ID: testPeerID2,
Addresses: []ma.Multiaddr{testMAddr},
Addresses: []ma.Multiaddr{testMAddr3},
Error: "abc",
},
}
@ -131,7 +133,7 @@ func TestMultiaddrConv(t *testing.T) {
t.Fatal("paniced")
}
}()
addrs := []ma.Multiaddr{testMAddr}
addrs := []ma.Multiaddr{testMAddr2}
new := MultiaddrsToSerial(addrs).ToMultiaddrs()
if !addrs[0].Equal(new[0]) {
t.Error("mismatch")

View File

@ -260,6 +260,7 @@ func (cfg *Config) LoadJSON(raw []byte) error {
clusterPeers := make([]ma.Multiaddr, len(jcfg.Peers))
for i := 0; i < len(jcfg.Peers); i++ {
fmt.Println([]byte(jcfg.Peers[i]))
maddr, err2 := ma.NewMultiaddr(jcfg.Peers[i])
if err2 != nil {
err = fmt.Errorf("error parsing multiaddress for peer %s: %s",

View File

@ -135,7 +135,8 @@ requires authorization. implies --https, which you can disable with --force-http
if c.Bool("debug") {
logging.SetLogLevel("cluster-ctl", "debug")
logging.SetLogLevel("apiclient", "debug")
cfg.LogLevel = "debug"
logger.Debug("debug level enabled")
}
enc := c.String("encoding")

View File

@ -389,6 +389,7 @@ var facilities = []string{
"descendalloc",
"diskinfo",
"config",
"apitypes",
}
func setupLogging(lvl string) {

View File

@ -15,6 +15,7 @@ var facilities = []string{
"pintracker",
"ascendalloc",
"diskinfo",
"apitypes",
}
// SetFacilityLogLevel sets the log level for a given module