master
go 195 lines 3.91 KB
Raw
1 package rpc
2
3 import (
4 "bytes"
5 "context"
6 "errors"
7
8 "github.com/ipfs/boxo/ipns"
9 "github.com/ipfs/boxo/path"
10 iface "github.com/ipfs/kubo/core/coreiface"
11 caopts "github.com/ipfs/kubo/core/coreiface/options"
12 "github.com/libp2p/go-libp2p/core/peer"
13 "github.com/multiformats/go-multibase"
14 )
15
16 type KeyAPI HttpApi
17
18 type key struct {
19 name string
20 pid peer.ID
21 path path.Path
22 }
23
24 func newKey(name, pidStr string) (*key, error) {
25 pid, err := peer.Decode(pidStr)
26 if err != nil {
27 return nil, err
28 }
29
30 path, err := path.NewPath("/ipns/" + ipns.NameFromPeer(pid).String())
31 if err != nil {
32 return nil, err
33 }
34
35 return &key{name: name, pid: pid, path: path}, nil
36 }
37
38 func (k *key) Name() string {
39 return k.name
40 }
41
42 func (k *key) Path() path.Path {
43 return k.path
44 }
45
46 func (k *key) ID() peer.ID {
47 return k.pid
48 }
49
50 type keyOutput struct {
51 Name string
52 Id string
53 }
54
55 func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.KeyGenerateOption) (iface.Key, error) {
56 options, err := caopts.KeyGenerateOptions(opts...)
57 if err != nil {
58 return nil, err
59 }
60
61 var out keyOutput
62 err = api.core().Request("key/gen", name).
63 Option("type", options.Algorithm).
64 Option("size", options.Size).
65 Exec(ctx, &out)
66 if err != nil {
67 return nil, err
68 }
69
70 return newKey(out.Name, out.Id)
71 }
72
73 func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, opts ...caopts.KeyRenameOption) (iface.Key, bool, error) {
74 options, err := caopts.KeyRenameOptions(opts...)
75 if err != nil {
76 return nil, false, err
77 }
78
79 var out struct {
80 Was string
81 Now string
82 Id string
83 Overwrite bool
84 }
85 err = api.core().Request("key/rename", oldName, newName).
86 Option("force", options.Force).
87 Exec(ctx, &out)
88 if err != nil {
89 return nil, false, err
90 }
91
92 key, err := newKey(out.Now, out.Id)
93 if err != nil {
94 return nil, false, err
95 }
96
97 return key, out.Overwrite, err
98 }
99
100 func (api *KeyAPI) List(ctx context.Context) ([]iface.Key, error) {
101 var out struct {
102 Keys []keyOutput
103 }
104 if err := api.core().Request("key/ls").Exec(ctx, &out); err != nil {
105 return nil, err
106 }
107
108 res := make([]iface.Key, len(out.Keys))
109 for i, k := range out.Keys {
110 key, err := newKey(k.Name, k.Id)
111 if err != nil {
112 return nil, err
113 }
114 res[i] = key
115 }
116
117 return res, nil
118 }
119
120 func (api *KeyAPI) Self(ctx context.Context) (iface.Key, error) {
121 var id struct{ ID string }
122 if err := api.core().Request("id").Exec(ctx, &id); err != nil {
123 return nil, err
124 }
125
126 return newKey("self", id.ID)
127 }
128
129 func (api *KeyAPI) Remove(ctx context.Context, name string) (iface.Key, error) {
130 var out struct {
131 Keys []keyOutput
132 }
133 if err := api.core().Request("key/rm", name).Exec(ctx, &out); err != nil {
134 return nil, err
135 }
136 if len(out.Keys) != 1 {
137 return nil, errors.New("got unexpected number of keys back")
138 }
139
140 return newKey(out.Keys[0].Name, out.Keys[0].Id)
141 }
142
143 func (api *KeyAPI) core() *HttpApi {
144 return (*HttpApi)(api)
145 }
146
147 func (api *KeyAPI) Sign(ctx context.Context, name string, data []byte) (iface.Key, []byte, error) {
148 var out struct {
149 Key keyOutput
150 Signature string
151 }
152
153 err := api.core().Request("key/sign").
154 Option("key", name).
155 FileBody(bytes.NewReader(data)).
156 Exec(ctx, &out)
157 if err != nil {
158 return nil, nil, err
159 }
160
161 key, err := newKey(out.Key.Name, out.Key.Id)
162 if err != nil {
163 return nil, nil, err
164 }
165
166 _, signature, err := multibase.Decode(out.Signature)
167 if err != nil {
168 return nil, nil, err
169 }
170
171 return key, signature, nil
172 }
173
174 func (api *KeyAPI) Verify(ctx context.Context, keyOrName string, signature, data []byte) (iface.Key, bool, error) {
175 var out struct {
176 Key keyOutput
177 SignatureValid bool
178 }
179
180 err := api.core().Request("key/verify").
181 Option("key", keyOrName).
182 Option("signature", toMultibase(signature)).
183 FileBody(bytes.NewReader(data)).
184 Exec(ctx, &out)
185 if err != nil {
186 return nil, false, err
187 }
188
189 key, err := newKey(out.Key.Name, out.Key.Id)
190 if err != nil {
191 return nil, false, err
192 }
193
194 return key, out.SignatureValid, nil
195 }