mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-29 09:34:03 +08:00
verify ipns records
This commit is contained in:
@ -156,6 +156,8 @@ func NewIpfsNode(cfg *config.Config, online bool) (n *IpfsNode, err error) {
|
|||||||
|
|
||||||
// setup routing service
|
// setup routing service
|
||||||
dhtRouting := dht.NewDHT(ctx, n.Identity, n.Peerstore, n.Network, dhtService, n.Datastore)
|
dhtRouting := dht.NewDHT(ctx, n.Identity, n.Peerstore, n.Network, dhtService, n.Datastore)
|
||||||
|
dhtRouting.Validators["ipns"] = namesys.ValidateIpnsRecord
|
||||||
|
|
||||||
// TODO(brian): perform this inside NewDHT factory method
|
// TODO(brian): perform this inside NewDHT factory method
|
||||||
dhtService.SetHandler(dhtRouting) // wire the handler to the service.
|
dhtService.SetHandler(dhtRouting) // wire the handler to the service.
|
||||||
n.Routing = dhtRouting
|
n.Routing = dhtRouting
|
||||||
|
@ -13,16 +13,49 @@ It has these top-level messages:
|
|||||||
*/
|
*/
|
||||||
package namesys_pb
|
package namesys_pb
|
||||||
|
|
||||||
import proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/proto"
|
import proto "code.google.com/p/gogoprotobuf/proto"
|
||||||
import math "math"
|
import math "math"
|
||||||
|
|
||||||
// Reference imports to suppress errors if they are not otherwise used.
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
var _ = proto.Marshal
|
var _ = proto.Marshal
|
||||||
var _ = math.Inf
|
var _ = math.Inf
|
||||||
|
|
||||||
|
type IpnsEntry_ValidityType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// setting an EOL says "this record is valid until..."
|
||||||
|
IpnsEntry_EOL IpnsEntry_ValidityType = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
var IpnsEntry_ValidityType_name = map[int32]string{
|
||||||
|
0: "EOL",
|
||||||
|
}
|
||||||
|
var IpnsEntry_ValidityType_value = map[string]int32{
|
||||||
|
"EOL": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x IpnsEntry_ValidityType) Enum() *IpnsEntry_ValidityType {
|
||||||
|
p := new(IpnsEntry_ValidityType)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
func (x IpnsEntry_ValidityType) String() string {
|
||||||
|
return proto.EnumName(IpnsEntry_ValidityType_name, int32(x))
|
||||||
|
}
|
||||||
|
func (x *IpnsEntry_ValidityType) UnmarshalJSON(data []byte) error {
|
||||||
|
value, err := proto.UnmarshalJSONEnum(IpnsEntry_ValidityType_value, data, "IpnsEntry_ValidityType")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*x = IpnsEntry_ValidityType(value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type IpnsEntry struct {
|
type IpnsEntry struct {
|
||||||
Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
|
Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
|
||||||
Signature []byte `protobuf:"bytes,2,req,name=signature" json:"signature,omitempty"`
|
Signature []byte `protobuf:"bytes,2,req,name=signature" json:"signature,omitempty"`
|
||||||
|
ValidityType *IpnsEntry_ValidityType `protobuf:"varint,3,opt,name=validityType,enum=namesys.pb.IpnsEntry_ValidityType" json:"validityType,omitempty"`
|
||||||
|
Validity []byte `protobuf:"bytes,4,opt,name=validity" json:"validity,omitempty"`
|
||||||
XXX_unrecognized []byte `json:"-"`
|
XXX_unrecognized []byte `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,5 +77,20 @@ func (m *IpnsEntry) GetSignature() []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func (m *IpnsEntry) GetValidityType() IpnsEntry_ValidityType {
|
||||||
|
if m != nil && m.ValidityType != nil {
|
||||||
|
return *m.ValidityType
|
||||||
|
}
|
||||||
|
return IpnsEntry_EOL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *IpnsEntry) GetValidity() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.Validity
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterEnum("namesys.pb.IpnsEntry_ValidityType", IpnsEntry_ValidityType_name, IpnsEntry_ValidityType_value)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
package namesys.pb;
|
package namesys.pb;
|
||||||
|
|
||||||
message IpnsEntry {
|
message IpnsEntry {
|
||||||
|
enum ValidityType {
|
||||||
|
// setting an EOL says "this record is valid until..."
|
||||||
|
EOL = 0;
|
||||||
|
}
|
||||||
required bytes value = 1;
|
required bytes value = 1;
|
||||||
required bytes signature = 2;
|
required bytes signature = 2;
|
||||||
|
|
||||||
|
optional ValidityType validityType = 3;
|
||||||
|
optional bytes validity = 4;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package namesys
|
package namesys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -14,6 +16,12 @@ import (
|
|||||||
u "github.com/jbenet/go-ipfs/util"
|
u "github.com/jbenet/go-ipfs/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrExpiredRecord should be returned when an ipns record is
|
||||||
|
// invalid due to being too old
|
||||||
|
var ErrExpiredRecord = errors.New("expired record")
|
||||||
|
|
||||||
|
var ErrUnrecognizedValidity = errors.New("unrecognized validity type")
|
||||||
|
|
||||||
// ipnsPublisher is capable of publishing and resolving names to the IPFS
|
// ipnsPublisher is capable of publishing and resolving names to the IPFS
|
||||||
// routing system.
|
// routing system.
|
||||||
type ipnsPublisher struct {
|
type ipnsPublisher struct {
|
||||||
@ -76,11 +84,48 @@ func (p *ipnsPublisher) Publish(k ci.PrivKey, value string) error {
|
|||||||
|
|
||||||
func createRoutingEntryData(pk ci.PrivKey, val string) ([]byte, error) {
|
func createRoutingEntryData(pk ci.PrivKey, val string) ([]byte, error) {
|
||||||
entry := new(pb.IpnsEntry)
|
entry := new(pb.IpnsEntry)
|
||||||
sig, err := pk.Sign([]byte(val))
|
|
||||||
|
entry.Value = []byte(val)
|
||||||
|
typ := pb.IpnsEntry_EOL
|
||||||
|
entry.ValidityType = &typ
|
||||||
|
entry.Validity = []byte(time.Now().Add(time.Hour * 24).String())
|
||||||
|
|
||||||
|
sig, err := pk.Sign(ipnsEntryDataForSig(entry))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
entry.Signature = sig
|
entry.Signature = sig
|
||||||
entry.Value = []byte(val)
|
|
||||||
return proto.Marshal(entry)
|
return proto.Marshal(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ipnsEntryDataForSig(e *pb.IpnsEntry) []byte {
|
||||||
|
return bytes.Join([][]byte{
|
||||||
|
e.Value,
|
||||||
|
e.Validity,
|
||||||
|
[]byte(fmt.Sprint(e.GetValidityType())),
|
||||||
|
},
|
||||||
|
[]byte{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidateIpnsRecord(k u.Key, val []byte) error {
|
||||||
|
entry := new(pb.IpnsEntry)
|
||||||
|
err := proto.Unmarshal(val, entry)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch entry.GetValidityType() {
|
||||||
|
case pb.IpnsEntry_EOL:
|
||||||
|
defaultTimeFormat := "2006-01-02 15:04:05.999999999 -0700 MST"
|
||||||
|
t, err := time.Parse(defaultTimeFormat, string(entry.GetValue()))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed parsing time for ipns record EOL")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if time.Now().After(t) {
|
||||||
|
return ErrExpiredRecord
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ErrUnrecognizedValidity
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -75,9 +75,11 @@ func (r *routingResolver) Resolve(name string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
hsh, _ := pk.Hash()
|
||||||
|
log.Debugf("pk hash = %s", u.Key(hsh))
|
||||||
|
|
||||||
// check sig with pk
|
// check sig with pk
|
||||||
if ok, err := pk.Verify(entry.GetValue(), entry.GetSignature()); err != nil || !ok {
|
if ok, err := pk.Verify(ipnsEntryDataForSig(entry), entry.GetSignature()); err != nil || !ok {
|
||||||
return "", fmt.Errorf("Invalid value. Not signed by PrivateKey corresponding to %v", pk)
|
return "", fmt.Errorf("Invalid value. Not signed by PrivateKey corresponding to %v", pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,6 @@ func NewDHT(ctx context.Context, p peer.Peer, ps peer.Peerstore, dialer inet.Dia
|
|||||||
dht.birth = time.Now()
|
dht.birth = time.Now()
|
||||||
|
|
||||||
dht.Validators = make(map[string]ValidatorFunc)
|
dht.Validators = make(map[string]ValidatorFunc)
|
||||||
dht.Validators["ipns"] = ValidateIpnsRecord
|
|
||||||
dht.Validators["pk"] = ValidatePublicKeyRecord
|
dht.Validators["pk"] = ValidatePublicKeyRecord
|
||||||
|
|
||||||
if doPinging {
|
if doPinging {
|
||||||
|
@ -96,11 +96,6 @@ func (dht *IpfsDHT) verifyRecord(r *pb.Record) error {
|
|||||||
return fnc(u.Key(r.GetKey()), r.GetValue())
|
return fnc(u.Key(r.GetKey()), r.GetValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateIpnsRecord(k u.Key, val []byte) error {
|
|
||||||
// TODO:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidatePublicKeyRecord(k u.Key, val []byte) error {
|
func ValidatePublicKeyRecord(k u.Key, val []byte) error {
|
||||||
keyparts := bytes.Split([]byte(k), []byte("/"))
|
keyparts := bytes.Split([]byte(k), []byte("/"))
|
||||||
if len(keyparts) < 3 {
|
if len(keyparts) < 3 {
|
||||||
|
Reference in New Issue
Block a user