From 235a7674929ec787c141abec96b11534023a159c Mon Sep 17 00:00:00 2001 From: Jeromy Date: Wed, 10 Sep 2014 16:55:49 +0000 Subject: [PATCH] implement namesys resolvers (thanks to bren2010 for dns and proquint) --- cmd/ipfs/pin.go | 44 +++++++++++++++++++++++++ core/core.go | 2 +- namesys/dns.go | 33 +++++++++++++++++++ namesys/entry.pb.go | 48 +++++++++++++++++++++++++++ namesys/entry.proto | 6 ++++ namesys/nsresolver.go | 5 +++ namesys/proquint.go | 22 +++++++++++++ namesys/resolver.go | 21 ++++++++++++ namesys/routing.go | 77 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 cmd/ipfs/pin.go create mode 100644 namesys/dns.go create mode 100644 namesys/entry.pb.go create mode 100644 namesys/entry.proto create mode 100644 namesys/nsresolver.go create mode 100644 namesys/proquint.go create mode 100644 namesys/resolver.go create mode 100644 namesys/routing.go diff --git a/cmd/ipfs/pin.go b/cmd/ipfs/pin.go new file mode 100644 index 000000000..88f8e8505 --- /dev/null +++ b/cmd/ipfs/pin.go @@ -0,0 +1,44 @@ +package main + +import ( + "os" + + "github.com/gonuts/flag" + "github.com/jbenet/commander" + "github.com/jbenet/go-ipfs/daemon" + u "github.com/jbenet/go-ipfs/util" +) + +var cmdIpfsPin = &commander.Command{ + UsageLine: "pin", + Short: "pin an ipfs object to local storage.", + Long: `ipfs pin - pin ipfs object to local storage. + + Retrieves the object named by and stores it locally + on disk. +`, + Run: pinCmd, + Flag: *flag.NewFlagSet("ipfs-pin", flag.ExitOnError), +} + +func pinCmd(c *commander.Command, inp []string) error { + if len(inp) < 1 { + u.POut(c.Long) + return nil + } + + com := daemon.NewCommand() + com.Command = "pin" + com.Args = inp + + err := daemon.SendCommand(com, "localhost:12345") + if err != nil { + n, err := localNode(false) + if err != nil { + return err + } + + daemon.ExecuteCommand(com, n, os.Stdout) + } + return nil +} diff --git a/core/core.go b/core/core.go index f641e8b2d..459a32aab 100644 --- a/core/core.go +++ b/core/core.go @@ -60,7 +60,7 @@ type IpfsNode struct { Resolver *path.Resolver // the name system, resolves paths to hashes - // Namesys *namesys.Namesys + Namesys namesys.NSResolver } // NewIpfsNode constructs a new IpfsNode based on the given config. diff --git a/namesys/dns.go b/namesys/dns.go new file mode 100644 index 000000000..b12bc0d38 --- /dev/null +++ b/namesys/dns.go @@ -0,0 +1,33 @@ +package namesys + +import ( + "net" + "strings" + + u "github.com/jbenet/go-ipfs/util" +) + +type DNSResolver struct { + // TODO: maybe some sort of caching? + // cache would need a timeout +} + +func (r *DNSResolver) Resolve(name string) (string, error) { + txt, err := net.LookupTXT(name) + if err != nil { + return "", err + } + + for _, t := range txt { + pair := strings.Split(t, "=") + if len(pair) < 2 { + // Log error? + u.DErr("Incorrectly formatted text record.") + continue + } + if pair[0] == name { + return pair[1], nil + } + } + return "", u.ErrNotFound +} diff --git a/namesys/entry.pb.go b/namesys/entry.pb.go new file mode 100644 index 000000000..c05efeb2f --- /dev/null +++ b/namesys/entry.pb.go @@ -0,0 +1,48 @@ +// Code generated by protoc-gen-go. +// source: entry.proto +// DO NOT EDIT! + +/* +Package namesys is a generated protocol buffer package. + +It is generated from these files: + entry.proto + +It has these top-level messages: + InpsEntry +*/ +package namesys + +import proto "code.google.com/p/goprotobuf/proto" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = math.Inf + +type InpsEntry struct { + Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"` + Signature []byte `protobuf:"bytes,2,req,name=signature" json:"signature,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *InpsEntry) Reset() { *m = InpsEntry{} } +func (m *InpsEntry) String() string { return proto.CompactTextString(m) } +func (*InpsEntry) ProtoMessage() {} + +func (m *InpsEntry) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func (m *InpsEntry) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +func init() { +} diff --git a/namesys/entry.proto b/namesys/entry.proto new file mode 100644 index 000000000..b7b09f041 --- /dev/null +++ b/namesys/entry.proto @@ -0,0 +1,6 @@ +package namesys; + +message InpsEntry { + required bytes value = 1; + required bytes signature = 2; +} diff --git a/namesys/nsresolver.go b/namesys/nsresolver.go new file mode 100644 index 000000000..ef5bc65cb --- /dev/null +++ b/namesys/nsresolver.go @@ -0,0 +1,5 @@ +package namesys + +type NSResolver interface { + Resolve(string) (string, error) +} diff --git a/namesys/proquint.go b/namesys/proquint.go new file mode 100644 index 000000000..8583a5390 --- /dev/null +++ b/namesys/proquint.go @@ -0,0 +1,22 @@ +package namesys + +import ( + "errors" + + proquint "github.com/bren2010/proquint" +) + +var _ = proquint.Encode + +type ProquintResolver struct{} + +func (r *ProquintResolver) Resolve(name string) (string, error) { + ok, err := proquint.IsProquint(name) + if err != nil { + return "", err + } + if !ok { + return "", errors.New("not a valid proquint string") + } + return string(proquint.Decode(name)), nil +} diff --git a/namesys/resolver.go b/namesys/resolver.go new file mode 100644 index 000000000..3498cbd46 --- /dev/null +++ b/namesys/resolver.go @@ -0,0 +1,21 @@ +package namesys + +import "strings" + +type MasterResolver struct { + dns *DNSResolver + routing *RoutingResolver + pro *ProquintResolver +} + +func (mr *MasterResolver) Resolve(name string) (string, error) { + if strings.Contains(name, ".") { + return mr.dns.Resolve(name) + } + + if strings.Contains(name, "-") { + return mr.pro.Resolve(name) + } + + return mr.routing.Resolve(name) +} diff --git a/namesys/routing.go b/namesys/routing.go new file mode 100644 index 000000000..f37b6485f --- /dev/null +++ b/namesys/routing.go @@ -0,0 +1,77 @@ +package namesys + +import ( + "fmt" + "time" + + "code.google.com/p/goprotobuf/proto" + + ci "github.com/jbenet/go-ipfs/crypto" + mdag "github.com/jbenet/go-ipfs/merkledag" + "github.com/jbenet/go-ipfs/routing" + u "github.com/jbenet/go-ipfs/util" + mh "github.com/jbenet/go-multihash" +) + +// RoutingName is the de-serialized name structure that is stored (serialized) +// in the routing system. Basically, a hash + a digital signature. (serialization can be +// protobuf, or a simple binary format) +type RoutingName struct { + Hash u.Key + Signature []byte +} + +// RoutingResolver implements NSResolver for the main IPFS SFS-like naming +type RoutingResolver struct { + routing routing.IpfsRouting + dag mdag.DAGService +} + +func (r *RoutingResolver) Resolve(name string) (string, error) { + hash, err := mh.FromB58String(name) + if err != nil { + return "", err + } + // name should be a multihash. if it isn't, error out here. + + // use the routing system to get the name. + // /ipns/ + h, err := u.Hash([]byte("ipns:" + name)) + if err != nil { + return "", err + } + + inpsKey := u.Key(h) + val, err := r.routing.GetValue(inpsKey, time.Second*10) + if err != nil { + return "", err + } + + entry := new(InpsEntry) + err = proto.Unmarshal(val, entry) + if err != nil { + return "", err + } + + // name should be a public key retrievable from ipfs + // /ipfs/ + key := u.Key(hash) + node, err := r.dag.Get(key) + if err != nil { + return "", err + } + + // get PublicKey from node.Data + pk, err := ci.UnmarshalPublicKey(node.Data) + if err != nil { + return "", err + } + + // check sig with pk + if ok, err := pk.Verify(entry.GetValue(), entry.GetSignature()); err != nil && ok { + return "", fmt.Errorf("Invalid value. Not signed by PrivateKey corresponding to %v", pk) + } + + // ok sig checks out. this is a valid name. + return string(entry.GetValue()), nil +}