verify ipns records
Jeromy committed
Nov 11, 2014 at 17:58 UTC
f21ec1923a7ea2ffeb82a87f6f08324adacb9f7b
7 files changed
+111
-13
core/core.go
+2
@@ -156,6 +156,8 @@ func NewIpfsNode(cfg *config.Config, online bool) (n *IpfsNode, err error) {
156
157
// setup routing service
158
dhtRouting := dht.NewDHT(ctx, n.Identity, n.Peerstore, n.Network, dhtService, n.Datastore)
159
+ dhtRouting.Validators["ipns"] = namesys.ValidateIpnsRecord
160
+
161
// TODO(brian): perform this inside NewDHT factory method
162
dhtService.SetHandler(dhtRouting) // wire the handler to the service.
163
n.Routing = dhtRouting
namesys/internal/pb/namesys.pb.go
+52
-4
@@ -13,17 +13,50 @@ It has these top-level messages:
13
*/
14
package namesys_pb
15
16
-import proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/proto"
16
+import proto "code.google.com/p/gogoprotobuf/proto"
17
import math "math"
18
19
// Reference imports to suppress errors if they are not otherwise used.
20
var _ = proto.Marshal
21
var _ = math.Inf
22
23
+type IpnsEntry_ValidityType int32
24
+
25
+const (
26
+ // setting an EOL says "this record is valid until..."
27
+ IpnsEntry_EOL IpnsEntry_ValidityType = 0
28
+)
29
+
30
+var IpnsEntry_ValidityType_name = map[int32]string{
31
+ 0: "EOL",
32
+}
33
+var IpnsEntry_ValidityType_value = map[string]int32{
34
+ "EOL": 0,
35
+}
36
+
37
+func (x IpnsEntry_ValidityType) Enum() *IpnsEntry_ValidityType {
38
+ p := new(IpnsEntry_ValidityType)
39
+ *p = x
40
+ return p
41
+}
42
+func (x IpnsEntry_ValidityType) String() string {
43
+ return proto.EnumName(IpnsEntry_ValidityType_name, int32(x))
44
+}
45
+func (x *IpnsEntry_ValidityType) UnmarshalJSON(data []byte) error {
46
+ value, err := proto.UnmarshalJSONEnum(IpnsEntry_ValidityType_value, data, "IpnsEntry_ValidityType")
47
+ if err != nil {
48
+ return err
49
+ }
50
+ *x = IpnsEntry_ValidityType(value)
51
+ return nil
52
+}
53
+
54
type IpnsEntry struct {
24
- Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
25
- Signature []byte `protobuf:"bytes,2,req,name=signature" json:"signature,omitempty"`
26
- XXX_unrecognized []byte `json:"-"`
55
+ Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
56
+ Signature []byte `protobuf:"bytes,2,req,name=signature" json:"signature,omitempty"`
57
+ ValidityType *IpnsEntry_ValidityType `protobuf:"varint,3,opt,name=validityType,enum=namesys.pb.IpnsEntry_ValidityType" json:"validityType,omitempty"`
58
+ Validity []byte `protobuf:"bytes,4,opt,name=validity" json:"validity,omitempty"`
59
+ XXX_unrecognized []byte `json:"-"`
60
}
61
62
func (m *IpnsEntry) Reset() { *m = IpnsEntry{} }
@@ -44,5 +77,20 @@ func (m *IpnsEntry) GetSignature() []byte {
77
return nil
78
}
79
80
+func (m *IpnsEntry) GetValidityType() IpnsEntry_ValidityType {
81
+ if m != nil && m.ValidityType != nil {
82
+ return *m.ValidityType
83
+ }
84
+ return IpnsEntry_EOL
85
+}
86
+
87
+func (m *IpnsEntry) GetValidity() []byte {
88
+ if m != nil {
89
+ return m.Validity
90
+ }
91
+ return nil
92
+}
93
+
94
func init() {
95
+ proto.RegisterEnum("namesys.pb.IpnsEntry_ValidityType", IpnsEntry_ValidityType_name, IpnsEntry_ValidityType_value)
96
}
namesys/internal/pb/namesys.proto
+7
@@ -1,6 +1,13 @@
1
package namesys.pb;
2
3
message IpnsEntry {
4
+ enum ValidityType {
5
+ // setting an EOL says "this record is valid until..."
6
+ EOL = 0;
7
+ }
8
required bytes value = 1;
9
required bytes signature = 2;
10
+
11
+ optional ValidityType validityType = 3;
12
+ optional bytes validity = 4;
13
}
namesys/publisher.go
+47
-2
@@ -1,6 +1,8 @@
1
package namesys
2
3
import (
4
+ "bytes"
5
+ "errors"
6
"fmt"
7
"time"
8
@@ -14,6 +16,12 @@ import (
16
u "github.com/jbenet/go-ipfs/util"
17
)
18
19
+// ErrExpiredRecord should be returned when an ipns record is
20
+// invalid due to being too old
21
+var ErrExpiredRecord = errors.New("expired record")
22
+
23
+var ErrUnrecognizedValidity = errors.New("unrecognized validity type")
24
+
25
// ipnsPublisher is capable of publishing and resolving names to the IPFS
26
// routing system.
27
type ipnsPublisher struct {
@@ -76,11 +84,48 @@ func (p *ipnsPublisher) Publish(k ci.PrivKey, value string) error {
84
85
func createRoutingEntryData(pk ci.PrivKey, val string) ([]byte, error) {
86
entry := new(pb.IpnsEntry)
79
- sig, err := pk.Sign([]byte(val))
87
+
88
+ entry.Value = []byte(val)
89
+ typ := pb.IpnsEntry_EOL
90
+ entry.ValidityType = &typ
91
+ entry.Validity = []byte(time.Now().Add(time.Hour * 24).String())
92
+
93
+ sig, err := pk.Sign(ipnsEntryDataForSig(entry))
94
if err != nil {
95
return nil, err
96
}
97
entry.Signature = sig
84
- entry.Value = []byte(val)
98
return proto.Marshal(entry)
99
}
100
+
101
+func ipnsEntryDataForSig(e *pb.IpnsEntry) []byte {
102
+ return bytes.Join([][]byte{
103
+ e.Value,
104
+ e.Validity,
105
+ []byte(fmt.Sprint(e.GetValidityType())),
106
+ },
107
+ []byte{})
108
+}
109
+
110
+func ValidateIpnsRecord(k u.Key, val []byte) error {
111
+ entry := new(pb.IpnsEntry)
112
+ err := proto.Unmarshal(val, entry)
113
+ if err != nil {
114
+ return err
115
+ }
116
+ switch entry.GetValidityType() {
117
+ case pb.IpnsEntry_EOL:
118
+ defaultTimeFormat := "2006-01-02 15:04:05.999999999 -0700 MST"
119
+ t, err := time.Parse(defaultTimeFormat, string(entry.GetValue()))
120
+ if err != nil {
121
+ log.Error("Failed parsing time for ipns record EOL")
122
+ return err
123
+ }
124
+ if time.Now().After(t) {
125
+ return ErrExpiredRecord
126
+ }
127
+ default:
128
+ return ErrUnrecognizedValidity
129
+ }
130
+ return nil
131
+}
namesys/routing.go
+3
-1
@@ -75,9 +75,11 @@ func (r *routingResolver) Resolve(name string) (string, error) {
75
if err != nil {
76
return "", err
77
}
78
+ hsh, _ := pk.Hash()
79
+ log.Debugf("pk hash = %s", u.Key(hsh))
80
81
// check sig with pk
80
- if ok, err := pk.Verify(entry.GetValue(), entry.GetSignature()); err != nil || !ok {
82
+ if ok, err := pk.Verify(ipnsEntryDataForSig(entry), entry.GetSignature()); err != nil || !ok {
83
return "", fmt.Errorf("Invalid value. Not signed by PrivateKey corresponding to %v", pk)
84
}
85
routing/dht/dht.go
-1
@@ -86,7 +86,6 @@ func NewDHT(ctx context.Context, p peer.Peer, ps peer.Peerstore, dialer inet.Dia
86
dht.birth = time.Now()
87
88
dht.Validators = make(map[string]ValidatorFunc)
89
- dht.Validators["ipns"] = ValidateIpnsRecord
89
dht.Validators["pk"] = ValidatePublicKeyRecord
90
91
if doPinging {
routing/dht/records.go
-5
@@ -96,11 +96,6 @@ func (dht *IpfsDHT) verifyRecord(r *pb.Record) error {
96
return fnc(u.Key(r.GetKey()), r.GetValue())
97
}
98
99
-func ValidateIpnsRecord(k u.Key, val []byte) error {
100
- // TODO:
101
- return nil
102
-}
103
-
99
func ValidatePublicKeyRecord(k u.Key, val []byte) error {
100
keyparts := bytes.Split([]byte(k), []byte("/"))
101
if len(keyparts) < 3 {