1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-07-04 21:38:51 +08:00

change ipns resolve/publish to store raw keys, not b58 encoded

This commit is contained in:
Jeromy
2015-01-26 20:13:11 +00:00
parent 56b14d8e9e
commit f1267d0624
14 changed files with 117 additions and 48 deletions

View File

@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"io" "io"
"strings"
"time" "time"
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
@ -45,6 +46,9 @@ if no peer is specified, prints out local peers info.
Arguments: []cmds.Argument{ Arguments: []cmds.Argument{
cmds.StringArg("peerid", false, false, "peer.ID of node to look up").EnableStdin(), cmds.StringArg("peerid", false, false, "peer.ID of node to look up").EnableStdin(),
}, },
Options: []cmds.Option{
cmds.StringOption("f", "format", "optional output format"),
},
Run: func(req cmds.Request, res cmds.Response) { Run: func(req cmds.Request, res cmds.Response) {
node, err := req.Context().GetNode() node, err := req.Context().GetNode()
if err != nil { if err != nil {
@ -101,11 +105,25 @@ if no peer is specified, prints out local peers info.
return nil, u.ErrCast() return nil, u.ErrCast()
} }
marshaled, err := json.MarshalIndent(val, "", "\t") format, found, err := res.Request().Option("format").String()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return bytes.NewReader(marshaled), nil if found {
output := format
output = strings.Replace(output, "<id>", val.ID, -1)
output = strings.Replace(output, "<aver>", val.AgentVersion, -1)
output = strings.Replace(output, "<pver>", val.ProtocolVersion, -1)
output = strings.Replace(output, "<pubkey>", val.PublicKey, -1)
return strings.NewReader(output), nil
} else {
marshaled, err := json.MarshalIndent(val, "", "\t")
if err != nil {
return nil, err
}
return bytes.NewReader(marshaled), nil
}
}, },
}, },
Type: IdOutput{}, Type: IdOutput{},

View File

@ -6,6 +6,8 @@ import (
"io" "io"
"strings" "strings"
b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
cmds "github.com/jbenet/go-ipfs/commands" cmds "github.com/jbenet/go-ipfs/commands"
core "github.com/jbenet/go-ipfs/core" core "github.com/jbenet/go-ipfs/core"
nsys "github.com/jbenet/go-ipfs/namesys" nsys "github.com/jbenet/go-ipfs/namesys"
@ -54,12 +56,16 @@ Publish a <ref> to another public key:
return return
} }
args := req.Arguments() if !n.OnlineMode() {
err := n.SetupOfflineRouting()
if n.PeerHost == nil { if err != nil {
res.SetError(errNotOnline, cmds.ErrClient) res.SetError(err, cmds.ErrNormal)
return
}
} }
args := req.Arguments()
if n.Identity == "" { if n.Identity == "" {
res.SetError(errors.New("Identity not loaded!"), cmds.ErrNormal) res.SetError(errors.New("Identity not loaded!"), cmds.ErrNormal)
return return
@ -98,7 +104,8 @@ Publish a <ref> to another public key:
func publish(n *core.IpfsNode, k crypto.PrivKey, ref string) (*IpnsEntry, error) { func publish(n *core.IpfsNode, k crypto.PrivKey, ref string) (*IpnsEntry, error) {
pub := nsys.NewRoutingPublisher(n.Routing) pub := nsys.NewRoutingPublisher(n.Routing)
err := pub.Publish(k, ref) val := b58.Decode(ref)
err := pub.Publish(n.Context(), k, u.Key(val))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -6,6 +6,7 @@ import (
"strings" "strings"
cmds "github.com/jbenet/go-ipfs/commands" cmds "github.com/jbenet/go-ipfs/commands"
u "github.com/jbenet/go-ipfs/util"
) )
var resolveCmd = &cmds.Command{ var resolveCmd = &cmds.Command{
@ -48,13 +49,16 @@ Resolve te value of another name:
return return
} }
var name string if !n.OnlineMode() {
err := n.SetupOfflineRouting()
if n.PeerHost == nil { if err != nil {
res.SetError(errNotOnline, cmds.ErrClient) res.SetError(err, cmds.ErrNormal)
return return
}
} }
var name string
if len(req.Arguments()) == 0 { if len(req.Arguments()) == 0 {
if n.Identity == "" { if n.Identity == "" {
res.SetError(errors.New("Identity not loaded!"), cmds.ErrNormal) res.SetError(errors.New("Identity not loaded!"), cmds.ErrNormal)
@ -66,7 +70,7 @@ Resolve te value of another name:
name = req.Arguments()[0] name = req.Arguments()[0]
} }
output, err := n.Namesys.Resolve(name) output, err := n.Namesys.Resolve(n.Context(), name)
if err != nil { if err != nil {
res.SetError(err, cmds.ErrNormal) res.SetError(err, cmds.ErrNormal)
return return
@ -78,8 +82,8 @@ Resolve te value of another name:
}, },
Marshalers: cmds.MarshalerMap{ Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) { cmds.Text: func(res cmds.Response) (io.Reader, error) {
output := res.Output().(string) output := res.Output().(u.Key)
return strings.NewReader(output), nil return strings.NewReader(output.B58String()), nil
}, },
}, },
} }

View File

@ -367,6 +367,9 @@ func (n *IpfsNode) SetupOfflineRouting() error {
} }
n.Routing = offroute.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey) n.Routing = offroute.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey)
n.Namesys = namesys.NewNameSystem(n.Routing)
return nil return nil
} }

View File

@ -3,6 +3,7 @@ package ipns
import ( import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
@ -252,7 +253,7 @@ func TestFastRepublish(t *testing.T) {
writeFileData(t, dataA, fname) // random writeFileData(t, dataA, fname) // random
<-time.After(shortRepublishTimeout * 2) <-time.After(shortRepublishTimeout * 2)
log.Debug("resolving first hash") log.Debug("resolving first hash")
resolvedHash, err := node.Namesys.Resolve(pubkeyHash) resolvedHash, err := node.Namesys.Resolve(context.Background(), pubkeyHash)
if err != nil { if err != nil {
t.Fatal("resolve err:", pubkeyHash, err) t.Fatal("resolve err:", pubkeyHash, err)
} }
@ -271,7 +272,7 @@ func TestFastRepublish(t *testing.T) {
}(shortRepublishTimeout) }(shortRepublishTimeout)
hasPublished := func() bool { hasPublished := func() bool {
res, err := node.Namesys.Resolve(pubkeyHash) res, err := node.Namesys.Resolve(context.Background(), pubkeyHash)
if err != nil { if err != nil {
t.Fatalf("resolve err: %v", err) t.Fatalf("resolve err: %v", err)
} }

View File

@ -38,7 +38,7 @@ var (
// point to an empty directory. // point to an empty directory.
func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error { func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error {
emptyDir := &mdag.Node{Data: ft.FolderPBData()} emptyDir := &mdag.Node{Data: ft.FolderPBData()}
k, err := n.DAG.Add(emptyDir) nodek, err := n.DAG.Add(emptyDir)
if err != nil { if err != nil {
return err return err
} }
@ -54,7 +54,7 @@ func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error {
} }
pub := nsys.NewRoutingPublisher(n.Routing) pub := nsys.NewRoutingPublisher(n.Routing)
err = pub.Publish(key, k.B58String()) err = pub.Publish(n.Context(), key, nodek)
if err != nil { if err != nil {
return err return err
} }
@ -116,7 +116,7 @@ func CreateRoot(n *core.IpfsNode, keys []ci.PrivKey, ipfsroot string) (*Root, er
go nd.repub.Run() go nd.repub.Run()
pointsTo, err := n.Namesys.Resolve(name) pointsTo, err := n.Namesys.Resolve(n.Context(), name)
if err != nil { if err != nil {
log.Warning("Could not resolve value for local ipns entry, providing empty dir") log.Warning("Could not resolve value for local ipns entry, providing empty dir")
nd.Nd = &mdag.Node{Data: ft.FolderPBData()} nd.Nd = &mdag.Node{Data: ft.FolderPBData()}
@ -124,12 +124,12 @@ func CreateRoot(n *core.IpfsNode, keys []ci.PrivKey, ipfsroot string) (*Root, er
continue continue
} }
if !u.IsValidHash(pointsTo) { if !u.IsValidHash(pointsTo.B58String()) {
log.Criticalf("Got back bad data from namesys resolve! [%s]", pointsTo) log.Criticalf("Got back bad data from namesys resolve! [%s]", pointsTo)
return nil, nil return nil, nil
} }
node, err := n.Resolver.ResolvePath(pointsTo) node, err := n.Resolver.ResolvePath(pointsTo.B58String())
if err != nil { if err != nil {
log.Warning("Failed to resolve value from ipns entry in ipfs") log.Warning("Failed to resolve value from ipns entry in ipfs")
continue continue
@ -186,13 +186,13 @@ func (s *Root) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
} }
log.Debugf("ipns: Falling back to resolution for [%s].", name) log.Debugf("ipns: Falling back to resolution for [%s].", name)
resolved, err := s.Ipfs.Namesys.Resolve(name) resolved, err := s.Ipfs.Namesys.Resolve(s.Ipfs.Context(), name)
if err != nil { if err != nil {
log.Warningf("ipns: namesys resolve error: %s", err) log.Warningf("ipns: namesys resolve error: %s", err)
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
return &Link{s.IpfsRoot + "/" + resolved}, nil return &Link{s.IpfsRoot + "/" + resolved.B58String()}, nil
} }
// ReadDir reads a particular directory. Disallowed for root. // ReadDir reads a particular directory. Disallowed for root.
@ -461,7 +461,7 @@ func (n *Node) republishRoot() error {
} }
log.Debug("Publishing changes!") log.Debug("Publishing changes!")
err = n.Ipfs.Namesys.Publish(root.key, ndkey.Pretty()) err = n.Ipfs.Namesys.Publish(n.Ipfs.Context(), root.key, ndkey)
if err != nil { if err != nil {
log.Errorf("ipns: Publish Failed: %s", err) log.Errorf("ipns: Publish Failed: %s", err)
return err return err

View File

@ -3,9 +3,12 @@ package namesys
import ( import (
"net" "net"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58" b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
isd "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-is-domain" isd "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-is-domain"
mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
u "github.com/jbenet/go-ipfs/util"
) )
// DNSResolver implements a Resolver on DNS domains // DNSResolver implements a Resolver on DNS domains
@ -22,7 +25,7 @@ func (r *DNSResolver) CanResolve(name string) bool {
// Resolve implements Resolver // Resolve implements Resolver
// TXT records for a given domain name should contain a b58 // TXT records for a given domain name should contain a b58
// encoded multihash. // encoded multihash.
func (r *DNSResolver) Resolve(name string) (string, error) { func (r *DNSResolver) Resolve(ctx context.Context, name string) (u.Key, error) {
log.Info("DNSResolver resolving %v", name) log.Info("DNSResolver resolving %v", name)
txt, err := net.LookupTXT(name) txt, err := net.LookupTXT(name)
if err != nil { if err != nil {
@ -39,7 +42,7 @@ func (r *DNSResolver) Resolve(name string) (string, error) {
if err != nil { if err != nil {
continue continue
} }
return t, nil return u.Key(chk), nil
} }
return "", ErrResolveFailed return "", ErrResolveFailed

View File

@ -3,7 +3,9 @@ package namesys
import ( import (
"errors" "errors"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
ci "github.com/jbenet/go-ipfs/p2p/crypto" ci "github.com/jbenet/go-ipfs/p2p/crypto"
u "github.com/jbenet/go-ipfs/util"
) )
// ErrResolveFailed signals an error when attempting to resolve. // ErrResolveFailed signals an error when attempting to resolve.
@ -28,7 +30,7 @@ type NameSystem interface {
type Resolver interface { type Resolver interface {
// Resolve looks up a name, and returns the value previously published. // Resolve looks up a name, and returns the value previously published.
Resolve(name string) (value string, err error) Resolve(ctx context.Context, name string) (value u.Key, err error)
// CanResolve checks whether this Resolver can resolve a name // CanResolve checks whether this Resolver can resolve a name
CanResolve(name string) bool CanResolve(name string) bool
@ -39,5 +41,5 @@ type Publisher interface {
// Publish establishes a name-value mapping. // Publish establishes a name-value mapping.
// TODO make this not PrivKey specific. // TODO make this not PrivKey specific.
Publish(name ci.PrivKey, value string) error Publish(ctx context.Context, name ci.PrivKey, value u.Key) error
} }

View File

@ -1,8 +1,10 @@
package namesys package namesys
import ( import (
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
ci "github.com/jbenet/go-ipfs/p2p/crypto" ci "github.com/jbenet/go-ipfs/p2p/crypto"
routing "github.com/jbenet/go-ipfs/routing" routing "github.com/jbenet/go-ipfs/routing"
u "github.com/jbenet/go-ipfs/util"
) )
// ipnsNameSystem implements IPNS naming. // ipnsNameSystem implements IPNS naming.
@ -32,10 +34,10 @@ func NewNameSystem(r routing.IpfsRouting) NameSystem {
} }
// Resolve implements Resolver // Resolve implements Resolver
func (ns *ipns) Resolve(name string) (string, error) { func (ns *ipns) Resolve(ctx context.Context, name string) (u.Key, error) {
for _, r := range ns.resolvers { for _, r := range ns.resolvers {
if r.CanResolve(name) { if r.CanResolve(name) {
return r.Resolve(name) return r.Resolve(ctx, name)
} }
} }
return "", ErrResolveFailed return "", ErrResolveFailed
@ -52,6 +54,6 @@ func (ns *ipns) CanResolve(name string) bool {
} }
// Publish implements Publisher // Publish implements Publisher
func (ns *ipns) Publish(name ci.PrivKey, value string) error { func (ns *ipns) Publish(ctx context.Context, name ci.PrivKey, value u.Key) error {
return ns.publisher.Publish(name, value) return ns.publisher.Publish(ctx, name, value)
} }

View File

@ -3,7 +3,9 @@ package namesys
import ( import (
"errors" "errors"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
proquint "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/bren2010/proquint" proquint "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/bren2010/proquint"
u "github.com/jbenet/go-ipfs/util"
) )
type ProquintResolver struct{} type ProquintResolver struct{}
@ -15,10 +17,10 @@ func (r *ProquintResolver) CanResolve(name string) bool {
} }
// Resolve implements Resolver. Decodes the proquint string. // Resolve implements Resolver. Decodes the proquint string.
func (r *ProquintResolver) Resolve(name string) (string, error) { func (r *ProquintResolver) Resolve(ctx context.Context, name string) (u.Key, error) {
ok := r.CanResolve(name) ok := r.CanResolve(name)
if !ok { if !ok {
return "", errors.New("not a valid proquint string") return "", errors.New("not a valid proquint string")
} }
return string(proquint.Decode(name)), nil return u.Key(proquint.Decode(name)), nil
} }

View File

@ -37,17 +37,16 @@ func NewRoutingPublisher(route routing.IpfsRouting) Publisher {
// Publish implements Publisher. Accepts a keypair and a value, // Publish implements Publisher. Accepts a keypair and a value,
// and publishes it out to the routing system // and publishes it out to the routing system
func (p *ipnsPublisher) Publish(k ci.PrivKey, value string) error { func (p *ipnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value u.Key) error {
log.Debugf("namesys: Publish %s", value) log.Debugf("namesys: Publish %s", value)
// validate `value` is a ref (multihash) // validate `value` is a ref (multihash)
_, err := mh.FromB58String(value) _, err := mh.FromB58String(value.Pretty())
if err != nil { if err != nil {
log.Errorf("hash cast failed: %s", value) log.Errorf("hash cast failed: %s", value)
return fmt.Errorf("publish value must be str multihash. %v", err) return fmt.Errorf("publish value must be str multihash. %v", err)
} }
ctx := context.TODO()
data, err := createRoutingEntryData(k, value) data, err := createRoutingEntryData(k, value)
if err != nil { if err != nil {
log.Error("entry creation failed.") log.Error("entry creation failed.")
@ -65,7 +64,7 @@ func (p *ipnsPublisher) Publish(k ci.PrivKey, value string) error {
log.Debugf("Storing pubkey at: %s", namekey) log.Debugf("Storing pubkey at: %s", namekey)
// Store associated public key // Store associated public key
timectx, _ := context.WithDeadline(ctx, time.Now().Add(time.Second*4)) timectx, _ := context.WithDeadline(ctx, time.Now().Add(time.Second*10))
err = p.routing.PutValue(timectx, namekey, pkbytes) err = p.routing.PutValue(timectx, namekey, pkbytes)
if err != nil { if err != nil {
return err return err
@ -75,7 +74,7 @@ func (p *ipnsPublisher) Publish(k ci.PrivKey, value string) error {
log.Debugf("Storing ipns entry at: %s", ipnskey) log.Debugf("Storing ipns entry at: %s", ipnskey)
// Store ipns entry at "/ipns/"+b58(h(pubkey)) // Store ipns entry at "/ipns/"+b58(h(pubkey))
timectx, _ = context.WithDeadline(ctx, time.Now().Add(time.Second*4)) timectx, _ = context.WithDeadline(ctx, time.Now().Add(time.Second*10))
err = p.routing.PutValue(timectx, ipnskey, data) err = p.routing.PutValue(timectx, ipnskey, data)
if err != nil { if err != nil {
return err return err
@ -84,7 +83,7 @@ func (p *ipnsPublisher) Publish(k ci.PrivKey, value string) error {
return nil return nil
} }
func createRoutingEntryData(pk ci.PrivKey, val string) ([]byte, error) { func createRoutingEntryData(pk ci.PrivKey, val u.Key) ([]byte, error) {
entry := new(pb.IpnsEntry) entry := new(pb.IpnsEntry)
entry.Value = []byte(val) entry.Value = []byte(val)

View File

@ -1,6 +1,7 @@
package namesys package namesys
import ( import (
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
"testing" "testing"
mockrouting "github.com/jbenet/go-ipfs/routing/mock" mockrouting "github.com/jbenet/go-ipfs/routing/mock"
@ -19,13 +20,13 @@ func TestRoutingResolve(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
err = publisher.Publish(privk, "Hello") err = publisher.Publish(context.Background(), privk, "Hello")
if err == nil { if err == nil {
t.Fatal("should have errored out when publishing a non-multihash val") t.Fatal("should have errored out when publishing a non-multihash val")
} }
h := u.Key(u.Hash([]byte("Hello"))).Pretty() h := u.Key(u.Hash([]byte("Hello")))
err = publisher.Publish(privk, h) err = publisher.Publish(context.Background(), privk, h)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -36,7 +37,7 @@ func TestRoutingResolve(t *testing.T) {
} }
pkhash := u.Hash(pubkb) pkhash := u.Hash(pubkb)
res, err := resolver.Resolve(u.Key(pkhash).Pretty()) res, err := resolver.Resolve(context.Background(), u.Key(pkhash).Pretty())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -38,9 +38,8 @@ func (r *routingResolver) CanResolve(name string) bool {
// Resolve implements Resolver. Uses the IPFS routing system to resolve SFS-like // Resolve implements Resolver. Uses the IPFS routing system to resolve SFS-like
// names. // names.
func (r *routingResolver) Resolve(name string) (string, error) { func (r *routingResolver) Resolve(ctx context.Context, name string) (u.Key, error) {
log.Debugf("RoutingResolve: '%s'", name) log.Debugf("RoutingResolve: '%s'", name)
ctx := context.TODO()
hash, err := mh.FromB58String(name) hash, err := mh.FromB58String(name)
if err != nil { if err != nil {
log.Warning("RoutingResolve: bad input hash: [%s]\n", name) log.Warning("RoutingResolve: bad input hash: [%s]\n", name)
@ -88,5 +87,5 @@ func (r *routingResolver) Resolve(name string) (string, error) {
} }
// ok sig checks out. this is a valid name. // ok sig checks out. this is a valid name.
return string(entry.GetValue()), nil return u.Key(entry.GetValue()), nil
} }

28
test/sharness/t0100-name.sh Executable file
View File

@ -0,0 +1,28 @@
#!/bin/sh
#
# Copyright (c) 2014 Jeromy Johnson
# MIT Licensed; see the LICENSE file in this repository.
#
test_description="Test ipfs repo operations"
. lib/test-lib.sh
test_init_ipfs
test_expect_success "'ipfs name publish' succeeds" '
PEERID=`ipfs id -format="<id>"` &&
HASH=QmYpv2VEsxzTTXRYX3PjDg961cnJE3kY1YDXLycHGQ3zZB &&
ipfs name publish $HASH > publish_out &&
echo Published name $PEERID to $HASH > expected1 &&
test_cmp publish_out expected1
'
test_expect_success "'ipfs name resolve' succeeds" '
ipfs name resolve $PEERID > output &&
printf "%s" $HASH > expected2 &&
test_cmp output expected2
'
test_done