@cryptotaxi247 / kubo / commits / 027f498bc

coreapi: Name API proposal

License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>

Łukasz Magiera committed Dec 10, 2017 at 23:15 UTC 027f498bc9faa37434c285b0293f5c9ba15aafb4
3 files changed +171
core/coreapi/coreapi.go
+4
@@ -29,6 +29,10 @@ func (api *CoreAPI) Dag() coreiface.DagAPI {
29 return &DagAPI{api, nil}
30 }
31
32 +func (api *CoreAPI) Name() coreiface.NameAPI {
33 + return (*NameAPI)(api)
34 +}
35 +
36 func (api *CoreAPI) ResolveNode(ctx context.Context, p coreiface.Path) (coreiface.Node, error) {
37 p, err := api.ResolvePath(ctx, p)
38 if err != nil {
core/coreapi/interface/interface.go
+19
@@ -6,6 +6,7 @@ import (
6 "context"
7 "errors"
8 "io"
9 + "time"
10
11 options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
12
@@ -27,6 +28,11 @@ type Path interface {
28 type Node ipld.Node
29 type Link ipld.Link
30
31 +type IpnsEntry struct {
32 + Name string
33 + Value Path
34 +}
35 +
36 type Reader interface {
37 io.ReadSeeker
38 io.Closer
@@ -37,6 +43,7 @@ type CoreAPI interface {
43 // Unixfs returns an implementation of Unixfs API
44 Unixfs() UnixfsAPI
45 Dag() DagAPI
46 + Name() NameAPI
47
48 // ResolvePath resolves the path using Unixfs resolver
49 ResolvePath(context.Context, Path) (Path, error)
@@ -90,6 +97,18 @@ type DagAPI interface {
97 WithDepth(depth int) options.DagTreeOption
98 }
99
100 +type NameAPI interface {
101 + Publish(ctx context.Context, path Path, validTime time.Duration, key string) (*IpnsEntry, error)
102 + Resolve(ctx context.Context, name string, recursive bool, local bool, nocache bool) (Path, error)
103 +}
104 +
105 +type KeyApi interface {
106 + Generate(ctx context.Context, name string, algorithm string, size int) error
107 + List(ctx context.Context) (map[string]string, error) //TODO: better key type?
108 + Rename(ctx context.Context, oldName string, newName string) error
109 + Remove(ctx context.Context, name string) error
110 +}
111 +
112 // type ObjectAPI interface {
113 // New() (cid.Cid, Object)
114 // Get(string) (Object, error)
core/coreapi/name.go new
+148
@@ -0,0 +1,148 @@
1 +package coreapi
2 +
3 +import (
4 + "context"
5 + "errors"
6 + "fmt"
7 + "strings"
8 + "time"
9 +
10 + core "github.com/ipfs/go-ipfs/core"
11 + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
12 + keystore "github.com/ipfs/go-ipfs/keystore"
13 + namesys "github.com/ipfs/go-ipfs/namesys"
14 + ipath "github.com/ipfs/go-ipfs/path"
15 + offline "github.com/ipfs/go-ipfs/routing/offline"
16 +
17 + peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
18 + crypto "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
19 +)
20 +
21 +type NameAPI CoreAPI
22 +
23 +func (api *NameAPI) Publish(ctx context.Context, p coreiface.Path, validTime time.Duration, key string) (*coreiface.IpnsEntry, error) {
24 + n := api.node
25 +
26 + if !n.OnlineMode() {
27 + err := n.SetupOfflineRouting()
28 + if err != nil {
29 + return nil, err
30 + }
31 + }
32 +
33 + if n.Mounts.Ipns != nil && n.Mounts.Ipns.IsActive() {
34 + return nil, errors.New("cannot manually publish while IPNS is mounted")
35 + }
36 +
37 + if n.Identity == "" {
38 + return nil, errors.New("identity not loaded")
39 + }
40 +
41 + pth, err := ipath.ParsePath(p.String())
42 + if err != nil {
43 + return nil, err
44 + }
45 +
46 + k, err := keylookup(n, key)
47 + if err != nil {
48 + return nil, err
49 + }
50 +
51 + eol := time.Now().Add(validTime)
52 + err = n.Namesys.PublishWithEOL(ctx, k, pth, eol)
53 + if err != nil {
54 + return nil, err
55 + }
56 +
57 + pid, err := peer.IDFromPrivateKey(k)
58 + if err != nil {
59 + return nil, err
60 + }
61 +
62 + return &coreiface.IpnsEntry{
63 + Name: pid.Pretty(),
64 + Value: p,
65 + }, nil
66 +}
67 +
68 +func (api *NameAPI) Resolve(ctx context.Context, name string, recursive bool, local bool, nocache bool) (coreiface.Path, error) {
69 + n := api.node
70 +
71 + if !n.OnlineMode() {
72 + err := n.SetupOfflineRouting()
73 + if err != nil {
74 + return nil, err
75 + }
76 + }
77 +
78 + var resolver namesys.Resolver = n.Namesys
79 +
80 + if local && nocache {
81 + return nil, errors.New("cannot specify both local and nocache")
82 + }
83 +
84 + if local {
85 + offroute := offline.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey)
86 + resolver = namesys.NewRoutingResolver(offroute, 0)
87 + }
88 +
89 + if nocache {
90 + resolver = namesys.NewNameSystem(n.Routing, n.Repo.Datastore(), 0)
91 + }
92 +
93 + depth := 1
94 + if recursive {
95 + depth = namesys.DefaultDepthLimit
96 + }
97 +
98 + if !strings.HasPrefix(name, "/ipns/") {
99 + name = "/ipns/" + name
100 + }
101 +
102 + output, err := resolver.ResolveN(ctx, name, depth)
103 + if err != nil {
104 + return nil, err
105 + }
106 +
107 + return &path{path: output}, nil
108 +}
109 +
110 +func (api *NameAPI) core() coreiface.CoreAPI {
111 + return (*CoreAPI)(api)
112 +}
113 +
114 +func keylookup(n *core.IpfsNode, k string) (crypto.PrivKey, error) {
115 + res, err := n.GetKey(k)
116 + if res != nil {
117 + return res, nil
118 + }
119 +
120 + if err != nil && err != keystore.ErrNoSuchKey {
121 + return nil, err
122 + }
123 +
124 + keys, err := n.Repo.Keystore().List()
125 + if err != nil {
126 + return nil, err
127 + }
128 +
129 + for _, key := range keys {
130 + privKey, err := n.Repo.Keystore().Get(key)
131 + if err != nil {
132 + return nil, err
133 + }
134 +
135 + pubKey := privKey.GetPublic()
136 +
137 + pid, err := peer.IDFromPublicKey(pubKey)
138 + if err != nil {
139 + return nil, err
140 + }
141 +
142 + if pid.Pretty() == k {
143 + return privKey, nil
144 + }
145 + }
146 +
147 + return nil, fmt.Errorf("no key by the given name or PeerID was found")
148 +}