@cryptotaxi247 / kubo / commits / 281d5eafb

Update ipns validator

License: MIT Signed-off-by: Dirk McCormick <dirkmdev@gmail.com>

Dirk McCormick committed Jan 20, 2018 at 17:25 UTC 281d5eafb4ed763047c70b8097881ab2a5654e4b
2 files changed +123 -2
namesys/ipns_validate_test.go new
+93
@@ -0,0 +1,93 @@
1 +package namesys
2 +
3 +import (
4 + "testing"
5 + "time"
6 +
7 + path "github.com/ipfs/go-ipfs/path"
8 + u "gx/ipfs/QmNiJuT8Ja3hMVpBHXv3Q6dwmperaQ6JjLtpMQgMCD7xvx/go-ipfs-util"
9 + proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
10 + ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
11 + record "gx/ipfs/QmbsY8Pr6s3uZsKg7rzBtGDKeCtdoAhNaMTCXBUbvb1eCV/go-libp2p-record"
12 +)
13 +
14 +func TestValidation(t *testing.T) {
15 + // Create a record validator
16 + validator := make(record.Validator)
17 + validator["ipns"] = &record.ValidChecker{ValidateIpnsRecord, true}
18 +
19 + // Generate a key for signing the records
20 + r := u.NewSeededRand(15) // generate deterministic keypair
21 + priv, pubk, err := ci.GenerateKeyPairWithReader(ci.RSA, 1024, r)
22 + if err != nil {
23 + t.Fatal(err)
24 + }
25 +
26 + // Create entry with expiry in one hour
27 + ts := time.Now()
28 + entry, err := CreateRoutingEntryData(priv, path.Path("foo"), 1, ts.Add(time.Hour))
29 + if err != nil {
30 + t.Fatal(err)
31 + }
32 +
33 + // Get IPNS record path
34 + pubkb, err := pubk.Bytes()
35 + if err != nil {
36 + t.Fatal(err)
37 + }
38 + pubkh := u.Hash(pubkb).B58String()
39 + ipnsPath := "/ipns/" + pubkh
40 +
41 + val, err := proto.Marshal(entry)
42 + if err != nil {
43 + t.Fatal(err)
44 + }
45 +
46 + // Create the record
47 + r1, err := record.MakePutRecord(priv, ipnsPath, val, true)
48 +
49 + // Validate the record
50 + err = validator.VerifyRecord(r1)
51 + if err != nil {
52 + t.Fatal(err)
53 + }
54 +
55 + // Create IPNS record path with a different key
56 + _, pubk2, err := ci.GenerateKeyPairWithReader(ci.RSA, 1024, r)
57 + if err != nil {
58 + t.Fatal(err)
59 + }
60 + pubkb2, err := pubk2.Bytes()
61 + if err != nil {
62 + t.Fatal(err)
63 + }
64 + pubkh2 := u.Hash(pubkb2).B58String()
65 + ipnsWrongPath := "/ipns/" + pubkh2
66 +
67 + r2, err := record.MakePutRecord(priv, ipnsWrongPath, val, true)
68 +
69 + // Record should fail validation because path doesn't match author
70 + err = validator.VerifyRecord(r2)
71 + if err != ErrInvalidAuthor {
72 + t.Fatal("ValidateIpnsRecord should have returned ErrInvalidAuthor")
73 + }
74 +
75 + // Create expired entry
76 + expired, err := CreateRoutingEntryData(priv, path.Path("foo"), 1, ts.Add(-1*time.Hour))
77 + if err != nil {
78 + t.Fatal(err)
79 + }
80 + valExp, err := proto.Marshal(expired)
81 + if err != nil {
82 + t.Fatal(err)
83 + }
84 +
85 + // Create record with the expired entry
86 + r3, err := record.MakePutRecord(priv, ipnsPath, valExp, true)
87 +
88 + // Record should fail validation because entry is expired
89 + err = validator.VerifyRecord(r3)
90 + if err != ErrExpiredRecord {
91 + t.Fatal("ValidateIpnsRecord should have returned ErrExpiredRecord")
92 + }
93 +}
namesys/publisher.go
+30 -2
@@ -5,6 +5,7 @@ import (
5 "context"
6 "errors"
7 "fmt"
8 + "strings"
9 "time"
10
11 pb "github.com/ipfs/go-ipfs/namesys/pb"
@@ -31,6 +32,14 @@ var ErrExpiredRecord = errors.New("expired record")
32 // unknown validity type.
33 var ErrUnrecognizedValidity = errors.New("unrecognized validity type")
34
35 +// ErrInvalidAuthor is returned when an IpnsRecord has an
36 +// author that does not match the IPNS path
37 +var ErrInvalidAuthor = errors.New("author does not match path")
38 +
39 +// ErrInvalidPath should be returned when an ipns record path
40 +// is not in a valid format
41 +var ErrInvalidPath = errors.New("record path invalid")
42 +
43 const PublishPutValTimeout = time.Minute
44 const DefaultRecordTTL = 24 * time.Hour
45
@@ -295,12 +304,31 @@ func selectRecord(recs []*pb.IpnsEntry, vals [][]byte) (int, error) {
304
305 // ValidateIpnsRecord implements ValidatorFunc and verifies that the
306 // given 'val' is an IpnsEntry and that that entry is valid.
298 -func ValidateIpnsRecord(k string, val []byte) error {
307 +func ValidateIpnsRecord(r *record.ValidationRecord) error {
308 + if r.Namespace != "ipns" {
309 + return ErrInvalidPath
310 + }
311 +
312 entry := new(pb.IpnsEntry)
300 - err := proto.Unmarshal(val, entry)
313 + err := proto.Unmarshal(r.Value, entry)
314 if err != nil {
315 return err
316 }
317 +
318 + // Note: The DHT will actually check the signature so we don't
319 + // need to do that here
320 +
321 + // Author in key must match author in record
322 + parts := strings.Split(r.Key, "/")
323 + pid, err := peer.IDB58Decode(parts[0])
324 + if err != nil {
325 + return ErrInvalidAuthor
326 + }
327 + if string(pid) != string(r.Author) {
328 + return ErrInvalidAuthor
329 + }
330 +
331 + // Check that record has not expired
332 switch entry.GetValidityType() {
333 case pb.IpnsEntry_EOL:
334 t, err := u.ParseRFC3339(string(entry.GetValidity()))