aboutsummaryrefslogtreecommitdiffstats
path: root/swarm/api/api.go
diff options
context:
space:
mode:
Diffstat (limited to 'swarm/api/api.go')
-rw-r--r--swarm/api/api.go129
1 files changed, 94 insertions, 35 deletions
diff --git a/swarm/api/api.go b/swarm/api/api.go
index 99d971b10..adf469cfa 100644
--- a/swarm/api/api.go
+++ b/swarm/api/api.go
@@ -19,6 +19,9 @@ package api
import (
"archive/tar"
"context"
+ "crypto/ecdsa"
+ "encoding/hex"
+ "errors"
"fmt"
"io"
"math/big"
@@ -44,6 +47,10 @@ import (
)
var (
+ ErrNotFound = errors.New("not found")
+)
+
+var (
apiResolveCount = metrics.NewRegisteredCounter("api.resolve.count", nil)
apiResolveFail = metrics.NewRegisteredCounter("api.resolve.fail", nil)
apiPutCount = metrics.NewRegisteredCounter("api.put.count", nil)
@@ -227,14 +234,18 @@ type API struct {
resource *mru.Handler
fileStore *storage.FileStore
dns Resolver
+ Decryptor func(context.Context, string) DecryptFunc
}
// NewAPI the api constructor initialises a new API instance.
-func NewAPI(fileStore *storage.FileStore, dns Resolver, resourceHandler *mru.Handler) (self *API) {
+func NewAPI(fileStore *storage.FileStore, dns Resolver, resourceHandler *mru.Handler, pk *ecdsa.PrivateKey) (self *API) {
self = &API{
fileStore: fileStore,
dns: dns,
resource: resourceHandler,
+ Decryptor: func(ctx context.Context, credentials string) DecryptFunc {
+ return self.doDecrypt(ctx, credentials, pk)
+ },
}
return
}
@@ -260,8 +271,30 @@ func (a *API) Store(ctx context.Context, data io.Reader, size int64, toEncrypt b
// ErrResolve is returned when an URI cannot be resolved from ENS.
type ErrResolve error
+// Resolve a name into a content-addressed hash
+// where address could be an ENS name, or a content addressed hash
+func (a *API) Resolve(ctx context.Context, address string) (storage.Address, error) {
+ // if DNS is not configured, return an error
+ if a.dns == nil {
+ if hashMatcher.MatchString(address) {
+ return common.Hex2Bytes(address), nil
+ }
+ apiResolveFail.Inc(1)
+ return nil, fmt.Errorf("no DNS to resolve name: %q", address)
+ }
+ // try and resolve the address
+ resolved, err := a.dns.Resolve(address)
+ if err != nil {
+ if hashMatcher.MatchString(address) {
+ return common.Hex2Bytes(address), nil
+ }
+ return nil, err
+ }
+ return resolved[:], nil
+}
+
// Resolve resolves a URI to an Address using the MultiResolver.
-func (a *API) Resolve(ctx context.Context, uri *URI) (storage.Address, error) {
+func (a *API) ResolveURI(ctx context.Context, uri *URI, credentials string) (storage.Address, error) {
apiResolveCount.Inc(1)
log.Trace("resolving", "uri", uri.Addr)
@@ -280,28 +313,44 @@ func (a *API) Resolve(ctx context.Context, uri *URI) (storage.Address, error) {
return key, nil
}
- // if DNS is not configured, check if the address is a hash
- if a.dns == nil {
- key := uri.Address()
- if key == nil {
- apiResolveFail.Inc(1)
- return nil, fmt.Errorf("no DNS to resolve name: %q", uri.Addr)
- }
- return key, nil
+ addr, err := a.Resolve(ctx, uri.Addr)
+ if err != nil {
+ return nil, err
}
- // try and resolve the address
- resolved, err := a.dns.Resolve(uri.Addr)
- if err == nil {
- return resolved[:], nil
+ if uri.Path == "" {
+ return addr, nil
}
-
- key := uri.Address()
- if key == nil {
- apiResolveFail.Inc(1)
+ walker, err := a.NewManifestWalker(ctx, addr, a.Decryptor(ctx, credentials), nil)
+ if err != nil {
return nil, err
}
- return key, nil
+ var entry *ManifestEntry
+ walker.Walk(func(e *ManifestEntry) error {
+ // if the entry matches the path, set entry and stop
+ // the walk
+ if e.Path == uri.Path {
+ entry = e
+ // return an error to cancel the walk
+ return errors.New("found")
+ }
+ // ignore non-manifest files
+ if e.ContentType != ManifestType {
+ return nil
+ }
+ // if the manifest's path is a prefix of the
+ // requested path, recurse into it by returning
+ // nil and continuing the walk
+ if strings.HasPrefix(uri.Path, e.Path) {
+ return nil
+ }
+ return ErrSkipManifest
+ })
+ if entry == nil {
+ return nil, errors.New("not found")
+ }
+ addr = storage.Address(common.Hex2Bytes(entry.Hash))
+ return addr, nil
}
// Put provides singleton manifest creation on top of FileStore store
@@ -332,10 +381,10 @@ func (a *API) Put(ctx context.Context, content string, contentType string, toEnc
// Get uses iterative manifest retrieval and prefix matching
// to resolve basePath to content using FileStore retrieve
// it returns a section reader, mimeType, status, the key of the actual content and an error
-func (a *API) Get(ctx context.Context, manifestAddr storage.Address, path string) (reader storage.LazySectionReader, mimeType string, status int, contentAddr storage.Address, err error) {
+func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage.Address, path string) (reader storage.LazySectionReader, mimeType string, status int, contentAddr storage.Address, err error) {
log.Debug("api.get", "key", manifestAddr, "path", path)
apiGetCount.Inc(1)
- trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil)
+ trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, decrypt)
if err != nil {
apiGetNotFound.Inc(1)
status = http.StatusNotFound
@@ -347,6 +396,16 @@ func (a *API) Get(ctx context.Context, manifestAddr storage.Address, path string
if entry != nil {
log.Debug("trie got entry", "key", manifestAddr, "path", path, "entry.Hash", entry.Hash)
+
+ if entry.ContentType == ManifestType {
+ log.Debug("entry is manifest", "key", manifestAddr, "new key", entry.Hash)
+ adr, err := hex.DecodeString(entry.Hash)
+ if err != nil {
+ return nil, "", 0, nil, err
+ }
+ return a.Get(ctx, decrypt, adr, entry.Path)
+ }
+
// we need to do some extra work if this is a mutable resource manifest
if entry.ContentType == ResourceContentType {
@@ -398,7 +457,7 @@ func (a *API) Get(ctx context.Context, manifestAddr storage.Address, path string
log.Trace("resource is multihash", "key", manifestAddr)
// get the manifest the multihash digest points to
- trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil)
+ trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, decrypt)
if err != nil {
apiGetNotFound.Inc(1)
status = http.StatusNotFound
@@ -451,7 +510,7 @@ func (a *API) Delete(ctx context.Context, addr string, path string) (storage.Add
apiDeleteFail.Inc(1)
return nil, err
}
- key, err := a.Resolve(ctx, uri)
+ key, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS)
if err != nil {
return nil, err
@@ -470,13 +529,13 @@ func (a *API) Delete(ctx context.Context, addr string, path string) (storage.Add
// GetDirectoryTar fetches a requested directory as a tarstream
// it returns an io.Reader and an error. Do not forget to Close() the returned ReadCloser
-func (a *API) GetDirectoryTar(ctx context.Context, uri *URI) (io.ReadCloser, error) {
+func (a *API) GetDirectoryTar(ctx context.Context, decrypt DecryptFunc, uri *URI) (io.ReadCloser, error) {
apiGetTarCount.Inc(1)
- addr, err := a.Resolve(ctx, uri)
+ addr, err := a.Resolve(ctx, uri.Addr)
if err != nil {
return nil, err
}
- walker, err := a.NewManifestWalker(ctx, addr, nil)
+ walker, err := a.NewManifestWalker(ctx, addr, decrypt, nil)
if err != nil {
apiGetTarFail.Inc(1)
return nil, err
@@ -542,9 +601,9 @@ func (a *API) GetDirectoryTar(ctx context.Context, uri *URI) (io.ReadCloser, err
// GetManifestList lists the manifest entries for the specified address and prefix
// and returns it as a ManifestList
-func (a *API) GetManifestList(ctx context.Context, addr storage.Address, prefix string) (list ManifestList, err error) {
+func (a *API) GetManifestList(ctx context.Context, decryptor DecryptFunc, addr storage.Address, prefix string) (list ManifestList, err error) {
apiManifestListCount.Inc(1)
- walker, err := a.NewManifestWalker(ctx, addr, nil)
+ walker, err := a.NewManifestWalker(ctx, addr, decryptor, nil)
if err != nil {
apiManifestListFail.Inc(1)
return ManifestList{}, err
@@ -631,7 +690,7 @@ func (a *API) UpdateManifest(ctx context.Context, addr storage.Address, update f
func (a *API) Modify(ctx context.Context, addr storage.Address, path, contentHash, contentType string) (storage.Address, error) {
apiModifyCount.Inc(1)
quitC := make(chan bool)
- trie, err := loadManifest(ctx, a.fileStore, addr, quitC)
+ trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt)
if err != nil {
apiModifyFail.Inc(1)
return nil, err
@@ -663,7 +722,7 @@ func (a *API) AddFile(ctx context.Context, mhash, path, fname string, content []
apiAddFileFail.Inc(1)
return nil, "", err
}
- mkey, err := a.Resolve(ctx, uri)
+ mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS)
if err != nil {
apiAddFileFail.Inc(1)
return nil, "", err
@@ -770,7 +829,7 @@ func (a *API) RemoveFile(ctx context.Context, mhash string, path string, fname s
apiRmFileFail.Inc(1)
return "", err
}
- mkey, err := a.Resolve(ctx, uri)
+ mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS)
if err != nil {
apiRmFileFail.Inc(1)
return "", err
@@ -837,7 +896,7 @@ func (a *API) AppendFile(ctx context.Context, mhash, path, fname string, existin
apiAppendFileFail.Inc(1)
return nil, "", err
}
- mkey, err := a.Resolve(ctx, uri)
+ mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS)
if err != nil {
apiAppendFileFail.Inc(1)
return nil, "", err
@@ -891,13 +950,13 @@ func (a *API) BuildDirectoryTree(ctx context.Context, mhash string, nameresolver
if err != nil {
return nil, nil, err
}
- addr, err = a.Resolve(ctx, uri)
+ addr, err = a.Resolve(ctx, uri.Addr)
if err != nil {
return nil, nil, err
}
quitC := make(chan bool)
- rootTrie, err := loadManifest(ctx, a.fileStore, addr, quitC)
+ rootTrie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt)
if err != nil {
return nil, nil, fmt.Errorf("can't load manifest %v: %v", addr.String(), err)
}
@@ -955,7 +1014,7 @@ func (a *API) ResourceHashSize() int {
// ResolveResourceManifest retrieves the Mutable Resource manifest for the given address, and returns the address of the metadata chunk.
func (a *API) ResolveResourceManifest(ctx context.Context, addr storage.Address) (storage.Address, error) {
- trie, err := loadManifest(ctx, a.fileStore, addr, nil)
+ trie, err := loadManifest(ctx, a.fileStore, addr, nil, NOOPDecrypt)
if err != nil {
return nil, fmt.Errorf("cannot load resource manifest: %v", err)
}