Skip to content

Commit

Permalink
feat: upgrade boxo for refactored boxo/ipns package
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Jun 14, 2023
1 parent c93e267 commit 07067dd
Show file tree
Hide file tree
Showing 21 changed files with 149 additions and 649 deletions.
24 changes: 7 additions & 17 deletions client/rpc/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,20 @@ import (
caopts "github.com/ipfs/boxo/coreiface/options"
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
"github.com/ipfs/boxo/coreiface/path"
"github.com/ipfs/boxo/ipns"
)

type NameAPI HttpApi

type ipnsEntry struct {
JName string `json:"Name"`
JValue string `json:"Value"`

path path.Path
}

func (e *ipnsEntry) Name() string {
return e.JName
Name string `json:"Name"`
Value string `json:"Value"`
}

func (e *ipnsEntry) Value() path.Path {
return e.path
}

func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.NamePublishOption) (iface.IpnsEntry, error) {
func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.NamePublishOption) (ipns.Name, error) {
options, err := caopts.NamePublishOptions(opts...)
if err != nil {
return nil, err
return ipns.Name{}, err
}

req := api.core().Request("name/publish", p.String()).
Expand All @@ -47,10 +38,9 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam

var out ipnsEntry
if err := req.Exec(ctx, &out); err != nil {
return nil, err
return ipns.Name{}, err
}
out.path = path.New(out.JValue)
return &out, out.path.IsValid()
return ipns.NameFromString(out.Name)
}

func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.NameResolveOption) (<-chan iface.IpnsResult, error) {
Expand Down
3 changes: 2 additions & 1 deletion cmd/ipfs/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
fsrepo "github.com/ipfs/kubo/repo/fsrepo"

options "github.com/ipfs/boxo/coreiface/options"
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
"github.com/ipfs/boxo/files"
cmds "github.com/ipfs/go-ipfs-cmds"
config "github.com/ipfs/kubo/config"
Expand Down Expand Up @@ -262,5 +263,5 @@ func initializeIpnsKeyspace(repoRoot string) error {
return err
}

return nd.Namesys.Publish(ctx, nd.PrivateKey, path.FromCid(emptyDir.Cid()))
return nd.Namesys.Publish(ctx, nd.PrivateKey, path.FromCid(emptyDir.Cid()), nsopts.PublishCompatibleWithV1(true))
}
11 changes: 1 addition & 10 deletions config/routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type Router struct {
Type RouterType

// Parameters are extra configuration that this router might need.
// A common one for reframe router is "Endpoint".
// A common one for HTTP router is "Endpoint".
Parameters interface{}
}

Expand Down Expand Up @@ -81,8 +81,6 @@ func (r *RouterParser) UnmarshalJSON(b []byte) error {
switch out.Type {
case RouterTypeHTTP:
p = &HTTPRouterParams{}
case RouterTypeReframe:
p = &ReframeRouterParams{}
case RouterTypeDHT:
p = &DHTRouterParams{}
case RouterTypeSequential:
Expand All @@ -106,7 +104,6 @@ func (r *RouterParser) UnmarshalJSON(b []byte) error {
type RouterType string

const (
RouterTypeReframe RouterType = "reframe" // More info here: https://github.com/ipfs/specs/tree/main/reframe . Actually deprecated.
RouterTypeHTTP RouterType = "http" // HTTP JSON API for delegated routing systems (IPIP-337).
RouterTypeDHT RouterType = "dht" // DHT router.
RouterTypeSequential RouterType = "sequential" // Router helper to execute several routers sequentially.
Expand All @@ -133,12 +130,6 @@ const (

var MethodNameList = []MethodName{MethodNameProvide, MethodNameFindPeers, MethodNameFindProviders, MethodNameGetIPNS, MethodNamePutIPNS}

type ReframeRouterParams struct {
// Endpoint is the URL where the routing implementation will point to get the information.
// Usually used for reframe Routers.
Endpoint string
}

type HTTPRouterParams struct {
// Endpoint is the URL where the routing implementation will point to get the information.
Endpoint string
Expand Down
77 changes: 12 additions & 65 deletions config/routing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ func TestRouterParameters(t *testing.T) {
PublicIPNetwork: false,
},
}},
"router-reframe": {Router{
Type: RouterTypeReframe,
Parameters: ReframeRouterParams{
Endpoint: "reframe-endpoint",
},
}},
"router-parallel": {Router{
Type: RouterTypeParallel,
Parameters: ComposableRouterParams{
Expand All @@ -39,7 +33,7 @@ func TestRouterParameters(t *testing.T) {
IgnoreErrors: true,
},
{
RouterName: "router-reframe",
RouterName: "router-dht",
Timeout: Duration{10 * time.Second},
IgnoreErrors: false,
ExecuteAfter: &OptionalDuration{&sec},
Expand All @@ -58,7 +52,7 @@ func TestRouterParameters(t *testing.T) {
IgnoreErrors: true,
},
{
RouterName: "router-reframe",
RouterName: "router-dht",
Timeout: Duration{10 * time.Second},
IgnoreErrors: false,
},
Expand All @@ -69,7 +63,7 @@ func TestRouterParameters(t *testing.T) {
},
Methods: Methods{
MethodNameFindPeers: {
RouterName: "router-reframe",
RouterName: "router-dht",
},
MethodNameFindProviders: {
RouterName: "router-dht",
Expand Down Expand Up @@ -99,95 +93,48 @@ func TestRouterParameters(t *testing.T) {
dhtp := r2.Routers["router-dht"].Parameters
require.IsType(&DHTRouterParams{}, dhtp)

rp := r2.Routers["router-reframe"].Parameters
require.IsType(&ReframeRouterParams{}, rp)

sp := r2.Routers["router-sequential"].Parameters
require.IsType(&ComposableRouterParams{}, sp)

pp := r2.Routers["router-parallel"].Parameters
require.IsType(&ComposableRouterParams{}, pp)
}

func TestRouterMissingParameters(t *testing.T) {
require := require.New(t)

r := Routing{
Type: NewOptionalString("custom"),
Routers: map[string]RouterParser{
"router-wrong-reframe": {Router{
Type: RouterTypeReframe,
Parameters: DHTRouterParams{
Mode: "auto",
AcceleratedDHTClient: true,
PublicIPNetwork: false,
},
}},
},
Methods: Methods{
MethodNameFindPeers: {
RouterName: "router-wrong-reframe",
},
MethodNameFindProviders: {
RouterName: "router-wrong-reframe",
},
MethodNameGetIPNS: {
RouterName: "router-wrong-reframe",
},
MethodNameProvide: {
RouterName: "router-wrong-reframe",
},
MethodNamePutIPNS: {
RouterName: "router-wrong-reframe",
},
},
}

out, err := json.Marshal(r)
require.NoError(err)

r2 := &Routing{}

err = json.Unmarshal(out, r2)
require.NoError(err)
require.Empty(r2.Routers["router-wrong-reframe"].Parameters.(*ReframeRouterParams).Endpoint)
}

func TestMethods(t *testing.T) {
require := require.New(t)

methodsOK := Methods{
MethodNameFindPeers: {
RouterName: "router-wrong-reframe",
RouterName: "router-wrong",
},
MethodNameFindProviders: {
RouterName: "router-wrong-reframe",
RouterName: "router-wrong",
},
MethodNameGetIPNS: {
RouterName: "router-wrong-reframe",
RouterName: "router-wrong",
},
MethodNameProvide: {
RouterName: "router-wrong-reframe",
RouterName: "router-wrong",
},
MethodNamePutIPNS: {
RouterName: "router-wrong-reframe",
RouterName: "router-wrong",
},
}

require.NoError(methodsOK.Check())

methodsMissing := Methods{
MethodNameFindPeers: {
RouterName: "router-wrong-reframe",
RouterName: "router-wrong",
},
MethodNameGetIPNS: {
RouterName: "router-wrong-reframe",
RouterName: "router-wrong",
},
MethodNameProvide: {
RouterName: "router-wrong-reframe",
RouterName: "router-wrong",
},
MethodNamePutIPNS: {
RouterName: "router-wrong-reframe",
RouterName: "router-wrong",
},
}

Expand Down
4 changes: 2 additions & 2 deletions core/commands/dht_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
func TestKeyTranslation(t *testing.T) {
pid := test.RandPeerIDFatal(t)
pkname := namesys.PkKeyForID(pid)
ipnsname := ipns.RecordKey(pid)
ipnsname := ipns.NameFromPeer(pid).RoutingKey()

pkk, err := escapeDhtKey("/pk/" + pid.Pretty())
if err != nil {
Expand All @@ -28,7 +28,7 @@ func TestKeyTranslation(t *testing.T) {
t.Fatal("keys didn't match!")
}

if ipnsk != ipnsname {
if ipnsk != string(ipnsname) {
t.Fatal("keys didn't match!")
}
}
59 changes: 38 additions & 21 deletions core/commands/name/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@ import (
"encoding/json"
"fmt"
"io"
"strings"
"text/tabwriter"
"time"

"github.com/gogo/protobuf/proto"
"github.com/ipfs/boxo/ipns"
ipns_pb "github.com/ipfs/boxo/ipns/pb"
cmds "github.com/ipfs/go-ipfs-cmds"
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"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/crypto"
mbase "github.com/multiformats/go-multibase"
"google.golang.org/protobuf/proto"
)

type IpnsEntry struct {
Expand Down Expand Up @@ -86,14 +85,14 @@ Resolve the value of a dnslink:
type IpnsInspectValidation struct {
Valid bool
Reason string
PublicKey peer.ID
PublicKey string
}

// 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
ValidityType *ipns_pb.IpnsRecord_ValidityType
Validity *time.Time
Sequence uint64
TTL *uint64
Expand Down Expand Up @@ -151,8 +150,17 @@ Passing --verify will verify signature against provided public key.
return err
}

var entry ipns_pb.IpnsEntry
err = proto.Unmarshal(b.Bytes(), &entry)
// Here we use the old school raw Protobuf pbRecord because we want to inspect it,
// aka, we need to be able to see all of its contents inside. While the boxo/ipns
// provides a good abstraction over the Record type, it doesn't allow for introspection
// of the raw value of the IpnsEntry.
var pbRecord ipns_pb.IpnsRecord
err = proto.Unmarshal(b.Bytes(), &pbRecord)
if err != nil {
return err
}

rec, err := ipns.UnmarshalRecord(b.Bytes())
if err != nil {
return err
}
Expand All @@ -164,24 +172,24 @@ Passing --verify will verify signature against provided public key.

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),
Value: string(pbRecord.Value),
ValidityType: pbRecord.ValidityType,
Sequence: *pbRecord.Sequence,
TTL: pbRecord.Ttl,
PublicKey: encoder.Encode(pbRecord.PubKey),
SignatureV1: encoder.Encode(pbRecord.SignatureV1),
SignatureV2: encoder.Encode(pbRecord.SignatureV2),
Data: nil,
},
}

if len(entry.Data) != 0 {
if len(pbRecord.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)
node, err := ipld.Decode(pbRecord.Data, dagcbor.Decode)
if err != nil {
return err
}
Expand All @@ -198,24 +206,33 @@ Passing --verify will verify signature against provided public key.
}
}

validity, err := ipns.GetEOL(&entry)
validity, err := rec.Validity()
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)
name, err := ipns.NameFromString(verify)
if err != nil {
return err
}

pk, err := ipns.ExtractPublicKey(rec, name)
if err != nil {
return err
}

bytes, err := crypto.MarshalPublicKey(pk)
if err != nil {
return err
}

result.Validation = &IpnsInspectValidation{
PublicKey: id,
PublicKey: encoder.Encode(bytes),
}

err = ipns.ValidateWithPeerID(id, &entry)
err = ipns.Validate(rec, pk)
if err == nil {
result.Validation.Valid = true
} else {
Expand Down
Loading

0 comments on commit 07067dd

Please sign in to comment.