Skip to content

Commit

Permalink
fix(ipns): honour --ttl flag in 'ipfs name publish' (#9471)
Browse files Browse the repository at this point in the history
* fix: honour --ttl flag in 'ipfs name publish'
* docs(cli): ipfs name inspect --help

Co-authored-by: Marcin Rataj <[email protected]>
  • Loading branch information
hacdias and lidel authored Jan 27, 2023
1 parent 9652f24 commit 94e7f79
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 30 deletions.
1 change: 1 addition & 0 deletions core/commands/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ func TestCommands(t *testing.T) {
"/multibase/transcode",
"/multibase/list",
"/name",
"/name/inspect",
"/name/publish",
"/name/pubsub",
"/name/pubsub/cancel",
Expand Down
219 changes: 218 additions & 1 deletion core/commands/name/name.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
package name

import (
"github.com/ipfs/go-ipfs-cmds"
"bytes"
"encoding/json"
"fmt"
"io"
"strings"
"text/tabwriter"
"time"

"github.com/gogo/protobuf/proto"
cmds "github.com/ipfs/go-ipfs-cmds"
"github.com/ipfs/go-ipns"
ipns_pb "github.com/ipfs/go-ipns/pb"
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagcbor"
"github.com/ipld/go-ipld-prime/codec/dagjson"
ic "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
mbase "github.com/multiformats/go-multibase"
)

type IpnsEntry struct {
Expand Down Expand Up @@ -62,5 +80,204 @@ Resolve the value of a dnslink:
"publish": PublishCmd,
"resolve": IpnsCmd,
"pubsub": IpnsPubsubCmd,
"inspect": IpnsInspectCmd,
},
}

type IpnsInspectValidation struct {
Valid bool
Reason string
PublicKey peer.ID
}

// IpnsInspectEntry contains the deserialized values from an IPNS Entry:
// https://github.com/ipfs/specs/blob/main/ipns/IPNS.md#record-serialization-format
type IpnsInspectEntry struct {
Value string
ValidityType *ipns_pb.IpnsEntry_ValidityType
Validity *time.Time
Sequence uint64
TTL *uint64
PublicKey string
SignatureV1 string
SignatureV2 string
Data interface{}
}

type IpnsInspectResult struct {
Entry IpnsInspectEntry
Validation *IpnsInspectValidation
}

var IpnsInspectCmd = &cmds.Command{
Status: cmds.Experimental,
Helptext: cmds.HelpText{
Tagline: "Inspects an IPNS Record",
ShortDescription: `
Prints values inside of IPNS Record protobuf and its DAG-CBOR Data field.
Passing --verify will verify signature against provided public key.
`,
LongDescription: `
Prints values inside of IPNS Record protobuf and its DAG-CBOR Data field.
The input can be a file or STDIN, the output can be JSON:
$ ipfs routing get "/ipns/$PEERID" > ipns_record
$ ipfs name inspect --enc=json < ipns_record
Values in PublicKey, SignatureV1 and SignatureV2 fields are raw bytes encoded
in Multibase. The Data field is DAG-CBOR represented as DAG-JSON.
Passing --verify will verify signature against provided public key.
`,
},
Arguments: []cmds.Argument{
cmds.FileArg("record", true, false, "The IPNS record payload to be verified.").EnableStdin(),
},
Options: []cmds.Option{
cmds.StringOption("verify", "CID of the public IPNS key to validate against."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
file, err := cmdenv.GetFileArg(req.Files.Entries())
if err != nil {
return err
}
defer file.Close()

var b bytes.Buffer

_, err = io.Copy(&b, file)
if err != nil {
return err
}

var entry ipns_pb.IpnsEntry
err = proto.Unmarshal(b.Bytes(), &entry)
if err != nil {
return err
}

encoder, err := mbase.EncoderByName("base64")
if err != nil {
return err
}

result := &IpnsInspectResult{
Entry: IpnsInspectEntry{
Value: string(entry.Value),
ValidityType: entry.ValidityType,
Sequence: *entry.Sequence,
TTL: entry.Ttl,
PublicKey: encoder.Encode(entry.PubKey),
SignatureV1: encoder.Encode(entry.SignatureV1),
SignatureV2: encoder.Encode(entry.SignatureV2),
Data: nil,
},
}

if len(entry.Data) != 0 {
// This is hacky. The variable node (datamodel.Node) doesn't directly marshal
// to JSON. Therefore, we need to first decode from DAG-CBOR, then encode in
// DAG-JSON and finally unmarshal it from JSON. Since DAG-JSON is a subset
// of JSON, that should work. Then, we can store the final value in the
// result.Entry.Data for further inspection.
node, err := ipld.Decode(entry.Data, dagcbor.Decode)
if err != nil {
return err
}

var buf bytes.Buffer
err = dagjson.Encode(node, &buf)
if err != nil {
return err
}

err = json.Unmarshal(buf.Bytes(), &result.Entry.Data)
if err != nil {
return err
}
}

validity, err := ipns.GetEOL(&entry)
if err == nil {
result.Entry.Validity = &validity
}

verify, ok := req.Options["verify"].(string)
if ok {
key := strings.TrimPrefix(verify, "/ipns/")
id, err := peer.Decode(key)
if err != nil {
return err
}

result.Validation = &IpnsInspectValidation{
PublicKey: id,
}

pub, err := id.ExtractPublicKey()
if err != nil {
// Make sure it works with all those RSA that cannot be embedded into the
// Peer ID.
if len(entry.PubKey) > 0 {
pub, err = ic.UnmarshalPublicKey(entry.PubKey)
}
}
if err != nil {
return err
}

err = ipns.Validate(pub, &entry)
if err == nil {
result.Validation.Valid = true
} else {
result.Validation.Reason = err.Error()
}
}

return cmds.EmitOnce(res, result)
},
Type: IpnsInspectResult{},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *IpnsInspectResult) error {
tw := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
defer tw.Flush()

fmt.Fprintf(tw, "Value:\t%q\n", string(out.Entry.Value))
fmt.Fprintf(tw, "Validity Type:\t%q\n", out.Entry.ValidityType)
if out.Entry.Validity != nil {
fmt.Fprintf(tw, "Validity:\t%s\n", out.Entry.Validity.Format(time.RFC3339Nano))
}
fmt.Fprintf(tw, "Sequence:\t%d\n", out.Entry.Sequence)
if out.Entry.TTL != nil {
fmt.Fprintf(tw, "TTL:\t%d\n", *out.Entry.TTL)
}
fmt.Fprintf(tw, "PublicKey:\t%q\n", out.Entry.PublicKey)
fmt.Fprintf(tw, "Signature V1:\t%q\n", out.Entry.SignatureV1)
fmt.Fprintf(tw, "Signature V2:\t%q\n", out.Entry.SignatureV2)

data, err := json.Marshal(out.Entry.Data)
if err != nil {
return err
}
fmt.Fprintf(tw, "Data:\t%s\n", string(data))

if out.Validation == nil {
tw.Flush()
fmt.Fprintf(w, "\nThis record was not validated.\n")
} else {
tw.Flush()
fmt.Fprintf(w, "\nValidation results:\n")

fmt.Fprintf(tw, "\tValid:\t%v\n", out.Validation.Valid)
if out.Validation.Reason != "" {
fmt.Fprintf(tw, "\tReason:\t%s\n", out.Validation.Reason)
}
fmt.Fprintf(tw, "\tPublicKey:\t%s\n", out.Validation.PublicKey)
}

return nil
}),
},
}
15 changes: 9 additions & 6 deletions core/coreapi/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
ipath "github.com/ipfs/go-path"
coreiface "github.com/ipfs/interface-go-ipfs-core"
caopts "github.com/ipfs/interface-go-ipfs-core/options"
nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
path "github.com/ipfs/interface-go-ipfs-core/path"
ci "github.com/libp2p/go-libp2p/core/crypto"
peer "github.com/libp2p/go-libp2p/core/peer"
Expand All @@ -37,8 +38,6 @@ func (e *ipnsEntry) Value() path.Path {
return e.value
}

type requestContextKey string

// Publish announces new IPNS name and returns the new IPNS entry.
func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.NamePublishOption) (coreiface.IpnsEntry, error) {
ctx, span := tracing.Span(ctx, "CoreAPI.NameAPI", "Publish", trace.WithAttributes(attribute.String("path", p.String())))
Expand Down Expand Up @@ -76,13 +75,17 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam
return nil, err
}

eol := time.Now().Add(options.ValidTime)

publishOptions := []nsopts.PublishOption{
nsopts.PublishWithEOL(eol),
}

if options.TTL != nil {
// nolint: staticcheck // non-backward compatible change
ctx = context.WithValue(ctx, requestContextKey("ipns-publish-ttl"), *options.TTL)
publishOptions = append(publishOptions, nsopts.PublishWithTTL(*options.TTL))
}

eol := time.Now().Add(options.ValidTime)
err = api.namesys.PublishWithEOL(ctx, k, pth, eol)
err = api.namesys.Publish(ctx, k, pth, publishOptions...)
if err != nil {
return nil, err
}
Expand Down
7 changes: 1 addition & 6 deletions core/corehttp/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"regexp"
"strings"
"testing"
"time"

namesys "github.com/ipfs/go-namesys"
version "github.com/ipfs/kubo"
Expand Down Expand Up @@ -68,11 +67,7 @@ func (m mockNamesys) ResolveAsync(ctx context.Context, name string, opts ...nsop
return out
}

func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Path) error {
return errors.New("not implemented for mockNamesys")
}

func (m mockNamesys) PublishWithEOL(ctx context.Context, name ci.PrivKey, value path.Path, _ time.Time) error {
func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Path, opts ...nsopts.PublishOption) error {
return errors.New("not implemented for mockNamesys")
}

Expand Down
8 changes: 4 additions & 4 deletions docs/examples/kubo-as-a-library/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ replace github.com/ipfs/kubo => ./../../..

require (
github.com/ipfs/go-libipfs v0.3.0
github.com/ipfs/interface-go-ipfs-core v0.8.2
github.com/ipfs/kubo v0.14.0-rc1
github.com/ipfs/interface-go-ipfs-core v0.9.0
github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
github.com/libp2p/go-libp2p v0.24.2
github.com/multiformats/go-multiaddr v0.8.0
)
Expand Down Expand Up @@ -101,7 +101,7 @@ require (
github.com/ipfs/go-merkledag v0.9.0 // indirect
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
github.com/ipfs/go-mfs v0.2.1 // indirect
github.com/ipfs/go-namesys v0.6.0 // indirect
github.com/ipfs/go-namesys v0.7.0 // indirect
github.com/ipfs/go-path v0.3.0 // indirect
github.com/ipfs/go-peertaskqueue v0.8.0 // indirect
github.com/ipfs/go-unixfs v0.4.2 // indirect
Expand Down Expand Up @@ -209,7 +209,7 @@ require (
golang.org/x/tools v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect
google.golang.org/grpc v1.47.0 // indirect
google.golang.org/grpc v1.46.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
Expand Down
11 changes: 5 additions & 6 deletions docs/examples/kubo-as-a-library/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -575,8 +575,8 @@ github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fG
github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY=
github.com/ipfs/go-mfs v0.2.1 h1:5jz8+ukAg/z6jTkollzxGzhkl3yxm022Za9f2nL5ab8=
github.com/ipfs/go-mfs v0.2.1/go.mod h1:Woj80iuw4ajDnIP6+seRaoHpPsc9hmL0pk/nDNDWP88=
github.com/ipfs/go-namesys v0.6.0 h1:w4+Wq9bCILnuZRT1RBBdzZQFqtJeDG1duzN8mIDnHZ0=
github.com/ipfs/go-namesys v0.6.0/go.mod h1:0L+3CHBgHxr08Cg+chVo9Ew285PGQfToThjll4g0/d4=
github.com/ipfs/go-namesys v0.7.0 h1:xqosk71GIVRkFDtF2UNRcXn4LdNeo7tzuy8feHD6NbU=
github.com/ipfs/go-namesys v0.7.0/go.mod h1:KYSZBVZG3VJC34EfqqJPG7T48aWgxseoMPAPA5gLyyQ=
github.com/ipfs/go-path v0.2.1/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I=
github.com/ipfs/go-path v0.3.0 h1:tkjga3MtpXyM5v+3EbRvOHEoo+frwi4oumw5K+KYWyA=
github.com/ipfs/go-path v0.3.0/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I=
Expand All @@ -594,8 +594,8 @@ github.com/ipfs/go-unixfsnode v1.5.1/go.mod h1:ed79DaG9IEuZITJVQn4U6MZDftv6I3ygU
github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0=
github.com/ipfs/go-verifcid v0.0.2 h1:XPnUv0XmdH+ZIhLGKg6U2vaPaRDXb9urMyNVCE7uvTs=
github.com/ipfs/go-verifcid v0.0.2/go.mod h1:40cD9x1y4OWnFXbLNJYRe7MpNvWlMn3LZAG5Wb4xnPU=
github.com/ipfs/interface-go-ipfs-core v0.8.2 h1:WDeCBnE4MENVOXbtfwwdAPJ2nBBS8PTmhZWWpm24HRM=
github.com/ipfs/interface-go-ipfs-core v0.8.2/go.mod h1:F3EcmDy53GFkF0H3iEJpfJC320fZ/4G60eftnItrrJ0=
github.com/ipfs/interface-go-ipfs-core v0.9.0 h1:+RCouVtSU/SldgkqWufjIu1smmGaSyKgUIfbYwLukgI=
github.com/ipfs/interface-go-ipfs-core v0.9.0/go.mod h1:F3EcmDy53GFkF0H3iEJpfJC320fZ/4G60eftnItrrJ0=
github.com/ipld/edelweiss v0.2.0 h1:KfAZBP8eeJtrLxLhi7r3N0cBCo7JmwSRhOJp3WSpNjk=
github.com/ipld/edelweiss v0.2.0/go.mod h1:FJAzJRCep4iI8FOFlRriN9n0b7OuX3T/S9++NpBDmA4=
github.com/ipld/go-car v0.4.0 h1:U6W7F1aKF/OJMHovnOVdst2cpQE5GhmHibQkAixgNcQ=
Expand Down Expand Up @@ -1779,9 +1779,8 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5
github.com/fsnotify/fsnotify v1.6.0
github.com/gabriel-vasile/mimetype v1.4.1
github.com/gogo/protobuf v1.3.2
github.com/google/uuid v1.3.0
github.com/hashicorp/go-multierror v1.1.1
github.com/ipfs/go-bitswap v0.11.0
Expand Down Expand Up @@ -55,13 +56,13 @@ require (
github.com/ipfs/go-metrics-interface v0.0.1
github.com/ipfs/go-metrics-prometheus v0.0.2
github.com/ipfs/go-mfs v0.2.1
github.com/ipfs/go-namesys v0.6.0
github.com/ipfs/go-namesys v0.7.0
github.com/ipfs/go-path v0.3.0
github.com/ipfs/go-pinning-service-http-client v0.1.2
github.com/ipfs/go-unixfs v0.4.2
github.com/ipfs/go-unixfsnode v1.5.1
github.com/ipfs/go-verifcid v0.0.2
github.com/ipfs/interface-go-ipfs-core v0.8.2
github.com/ipfs/interface-go-ipfs-core v0.9.0
github.com/ipld/go-car v0.4.0
github.com/ipld/go-car/v2 v2.5.1
github.com/ipld/go-codec-dagpb v1.5.0
Expand Down Expand Up @@ -142,7 +143,6 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
Expand Down
Loading

0 comments on commit 94e7f79

Please sign in to comment.