mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 01:43:47 +00:00
Merge pull request #380 from ethersphere/encryption-cmd-api
Command line encryption api
This commit is contained in:
commit
9e0db9817c
16 changed files with 164 additions and 65 deletions
|
|
@ -141,6 +141,10 @@ var (
|
||||||
Name: "mime",
|
Name: "mime",
|
||||||
Usage: "force mime type",
|
Usage: "force mime type",
|
||||||
}
|
}
|
||||||
|
SwarmEncryptedFlag = cli.BoolFlag{
|
||||||
|
Name: "encrypted",
|
||||||
|
Usage: "use encrypted upload",
|
||||||
|
}
|
||||||
SwarmPssEnabledFlag = cli.BoolFlag{
|
SwarmPssEnabledFlag = cli.BoolFlag{
|
||||||
Name: "pss",
|
Name: "pss",
|
||||||
Usage: "Enable pss (message passing over swarm)",
|
Usage: "Enable pss (message passing over swarm)",
|
||||||
|
|
@ -222,6 +226,7 @@ The output of this command is supposed to be machine-readable.
|
||||||
Name: "up",
|
Name: "up",
|
||||||
Usage: "upload a file or directory to swarm using the HTTP API",
|
Usage: "upload a file or directory to swarm using the HTTP API",
|
||||||
ArgsUsage: " <file>",
|
ArgsUsage: " <file>",
|
||||||
|
Flags: []cli.Flag{SwarmEncryptedFlag},
|
||||||
Description: `
|
Description: `
|
||||||
"upload a file or directory to swarm using the HTTP API and prints the root hash",
|
"upload a file or directory to swarm using the HTTP API and prints the root hash",
|
||||||
`,
|
`,
|
||||||
|
|
|
||||||
|
|
@ -131,13 +131,13 @@ func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) strin
|
||||||
longestPathEntry = api.ManifestEntry{}
|
longestPathEntry = api.ManifestEntry{}
|
||||||
)
|
)
|
||||||
|
|
||||||
mroot, err := client.DownloadManifest(mhash)
|
mroot, isEncrypted, err := client.DownloadManifest(mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Manifest download failed: %v", err)
|
utils.Fatalf("Manifest download failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: check if the "hash" to add is valid and present in swarm
|
//TODO: check if the "hash" to add is valid and present in swarm
|
||||||
_, err = client.DownloadManifest(hash)
|
_, _, err = client.DownloadManifest(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Hash to add is not present: %v", err)
|
utils.Fatalf("Hash to add is not present: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -180,7 +180,7 @@ func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) strin
|
||||||
mroot.Entries = append(mroot.Entries, newEntry)
|
mroot.Entries = append(mroot.Entries, newEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
newManifestHash, err := client.UploadManifest(mroot)
|
newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Manifest upload failed: %v", err)
|
utils.Fatalf("Manifest upload failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -197,7 +197,7 @@ func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) st
|
||||||
longestPathEntry = api.ManifestEntry{}
|
longestPathEntry = api.ManifestEntry{}
|
||||||
)
|
)
|
||||||
|
|
||||||
mroot, err := client.DownloadManifest(mhash)
|
mroot, isEncrypted, err := client.DownloadManifest(mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Manifest download failed: %v", err)
|
utils.Fatalf("Manifest download failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -257,7 +257,7 @@ func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) st
|
||||||
mroot = newMRoot
|
mroot = newMRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
newManifestHash, err := client.UploadManifest(mroot)
|
newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Manifest upload failed: %v", err)
|
utils.Fatalf("Manifest upload failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +273,7 @@ func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
|
||||||
longestPathEntry = api.ManifestEntry{}
|
longestPathEntry = api.ManifestEntry{}
|
||||||
)
|
)
|
||||||
|
|
||||||
mroot, err := client.DownloadManifest(mhash)
|
mroot, isEncrypted, err := client.DownloadManifest(mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Manifest download failed: %v", err)
|
utils.Fatalf("Manifest download failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -323,7 +323,7 @@ func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
|
||||||
mroot = newMRoot
|
mroot = newMRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
newManifestHash, err := client.UploadManifest(mroot)
|
newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Manifest upload failed: %v", err)
|
utils.Fatalf("Manifest upload failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ func upload(ctx *cli.Context) {
|
||||||
fromStdin = ctx.GlobalBool(SwarmUpFromStdinFlag.Name)
|
fromStdin = ctx.GlobalBool(SwarmUpFromStdinFlag.Name)
|
||||||
mimeType = ctx.GlobalString(SwarmUploadMimeType.Name)
|
mimeType = ctx.GlobalString(SwarmUploadMimeType.Name)
|
||||||
client = swarm.NewClient(bzzapi)
|
client = swarm.NewClient(bzzapi)
|
||||||
|
toEncrypt = ctx.Bool(SwarmEncryptedFlag.Name)
|
||||||
file string
|
file string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -76,7 +77,7 @@ func upload(ctx *cli.Context) {
|
||||||
utils.Fatalf("Error opening file: %s", err)
|
utils.Fatalf("Error opening file: %s", err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
hash, err := client.UploadRaw(f, f.Size)
|
hash, err := client.UploadRaw(f, f.Size, toEncrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Upload failed: %s", err)
|
utils.Fatalf("Upload failed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +98,7 @@ func upload(ctx *cli.Context) {
|
||||||
if !recursive {
|
if !recursive {
|
||||||
return "", errors.New("Argument is a directory and recursive upload is disabled")
|
return "", errors.New("Argument is a directory and recursive upload is disabled")
|
||||||
}
|
}
|
||||||
return client.UploadDirectory(file, defaultPath, "")
|
return client.UploadDirectory(file, defaultPath, "", toEncrypt)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
doUpload = func() (string, error) {
|
doUpload = func() (string, error) {
|
||||||
|
|
@ -110,7 +111,7 @@ func upload(ctx *cli.Context) {
|
||||||
mimeType = detectMimeType(file)
|
mimeType = detectMimeType(file)
|
||||||
}
|
}
|
||||||
f.ContentType = mimeType
|
f.ContentType = mimeType
|
||||||
return client.Upload(f, "")
|
return client.Upload(f, "", toEncrypt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hash, err := doUpload()
|
hash, err := doUpload()
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -29,6 +30,16 @@ import (
|
||||||
// TestCLISwarmUp tests that running 'swarm up' makes the resulting file
|
// TestCLISwarmUp tests that running 'swarm up' makes the resulting file
|
||||||
// available from all nodes via the HTTP API
|
// available from all nodes via the HTTP API
|
||||||
func TestCLISwarmUp(t *testing.T) {
|
func TestCLISwarmUp(t *testing.T) {
|
||||||
|
testCLISwarmUp(false, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCLISwarmUpEncrypted tests that running 'swarm encrypted-up' makes the resulting file
|
||||||
|
// available from all nodes via the HTTP API
|
||||||
|
func TestCLISwarmUpEncrypted(t *testing.T) {
|
||||||
|
testCLISwarmUp(true, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCLISwarmUp(toEncrypt bool, t *testing.T) {
|
||||||
log.Info("starting 3 node cluster")
|
log.Info("starting 3 node cluster")
|
||||||
cluster := newTestCluster(t, 3)
|
cluster := newTestCluster(t, 3)
|
||||||
defer cluster.Shutdown()
|
defer cluster.Shutdown()
|
||||||
|
|
@ -48,10 +59,23 @@ func TestCLISwarmUp(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashRegexp := `[a-f\d]{64}`
|
||||||
|
flags := []string{
|
||||||
|
"--bzzapi", cluster.Nodes[0].URL,
|
||||||
|
"up",
|
||||||
|
tmp.Name()}
|
||||||
|
if toEncrypt {
|
||||||
|
hashRegexp = `[a-f\d]{128}`
|
||||||
|
flags = []string{
|
||||||
|
"--bzzapi", cluster.Nodes[0].URL,
|
||||||
|
"up",
|
||||||
|
"--encrypted",
|
||||||
|
tmp.Name()}
|
||||||
|
}
|
||||||
// upload the file with 'swarm up' and expect a hash
|
// upload the file with 'swarm up' and expect a hash
|
||||||
log.Info("uploading file with 'swarm up'")
|
log.Info(fmt.Sprintf("uploading file with 'swarm up'"))
|
||||||
up := runSwarm(t, "--bzzapi", cluster.Nodes[0].URL, "up", tmp.Name())
|
up := runSwarm(t, flags...)
|
||||||
_, matches := up.ExpectRegexp(`[a-f\d]{64}`)
|
_, matches := up.ExpectRegexp(hashRegexp)
|
||||||
up.ExpectExit()
|
up.ExpectExit()
|
||||||
hash := matches[0]
|
hash := matches[0]
|
||||||
log.Info("file uploaded", "hash", hash)
|
log.Info("file uploaded", "hash", hash)
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,7 @@ func (self *Api) Upload(uploadDir, index string, toEncrypt bool) (hash string, e
|
||||||
}
|
}
|
||||||
|
|
||||||
// DPA reader API
|
// DPA reader API
|
||||||
func (self *Api) Retrieve(key storage.Key) storage.LazySectionReader {
|
func (self *Api) Retrieve(key storage.Key) (reader storage.LazySectionReader, isEncrypted bool) {
|
||||||
return self.dpa.Retrieve(key)
|
return self.dpa.Retrieve(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -344,7 +344,7 @@ func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionRe
|
||||||
} else {
|
} else {
|
||||||
mimeType = entry.ContentType
|
mimeType = entry.ContentType
|
||||||
log.Trace("content lookup key", "key", key, "mimetype", mimeType)
|
log.Trace("content lookup key", "key", key, "mimetype", mimeType)
|
||||||
reader = self.dpa.Retrieve(key)
|
reader, _ = self.dpa.Retrieve(key)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
status = http.StatusNotFound
|
status = http.StatusNotFound
|
||||||
|
|
@ -482,7 +482,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
|
|
||||||
buf := make([]byte, buffSize)
|
buf := make([]byte, buffSize)
|
||||||
|
|
||||||
oldReader := self.Retrieve(oldKey)
|
oldReader, _ := self.Retrieve(oldKey)
|
||||||
io.ReadAtLeast(oldReader, buf, int(offset))
|
io.ReadAtLeast(oldReader, buf, int(offset))
|
||||||
|
|
||||||
newReader := bytes.NewReader(content)
|
newReader := bytes.NewReader(content)
|
||||||
|
|
|
||||||
|
|
@ -52,12 +52,17 @@ type Client struct {
|
||||||
Gateway string
|
Gateway string
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadRaw uploads raw data to swarm and returns the resulting hash
|
// UploadRaw uploads raw data to swarm and returns the resulting hash. If toEncrypt is true it
|
||||||
func (c *Client) UploadRaw(r io.Reader, size int64) (string, error) {
|
// uploads encrypted data
|
||||||
|
func (c *Client) UploadRaw(r io.Reader, size int64, toEncrypt bool) (string, error) {
|
||||||
if size <= 0 {
|
if size <= 0 {
|
||||||
return "", errors.New("data size must be greater than zero")
|
return "", errors.New("data size must be greater than zero")
|
||||||
}
|
}
|
||||||
req, err := http.NewRequest("POST", c.Gateway+"/bzz-raw:/", r)
|
addr := ""
|
||||||
|
if toEncrypt {
|
||||||
|
addr = "encrypt"
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST", c.Gateway+"/bzz-raw:/"+addr, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -77,18 +82,20 @@ func (c *Client) UploadRaw(r io.Reader, size int64) (string, error) {
|
||||||
return string(data), nil
|
return string(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadRaw downloads raw data from swarm
|
// DownloadRaw downloads raw data from swarm and it returns a ReadCloser and a bool whether the
|
||||||
func (c *Client) DownloadRaw(hash string) (io.ReadCloser, error) {
|
// content was encrypted
|
||||||
|
func (c *Client) DownloadRaw(hash string) (io.ReadCloser, bool, error) {
|
||||||
uri := c.Gateway + "/bzz-raw:/" + hash
|
uri := c.Gateway + "/bzz-raw:/" + hash
|
||||||
res, err := http.DefaultClient.Get(uri)
|
res, err := http.DefaultClient.Get(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
return nil, fmt.Errorf("unexpected HTTP status: %s", res.Status)
|
return nil, false, fmt.Errorf("unexpected HTTP status: %s", res.Status)
|
||||||
}
|
}
|
||||||
return res.Body, nil
|
isEncrypted := (res.Header.Get("X-Decrypted") == "true")
|
||||||
|
return res.Body, isEncrypted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// File represents a file in a swarm manifest and is used for uploading and
|
// File represents a file in a swarm manifest and is used for uploading and
|
||||||
|
|
@ -125,11 +132,11 @@ func Open(path string) (*File, error) {
|
||||||
// (if the manifest argument is non-empty) or creates a new manifest containing
|
// (if the manifest argument is non-empty) or creates a new manifest containing
|
||||||
// the file, returning the resulting manifest hash (the file will then be
|
// the file, returning the resulting manifest hash (the file will then be
|
||||||
// available at bzz:/<hash>/<path>)
|
// available at bzz:/<hash>/<path>)
|
||||||
func (c *Client) Upload(file *File, manifest string) (string, error) {
|
func (c *Client) Upload(file *File, manifest string, toEncrypt bool) (string, error) {
|
||||||
if file.Size <= 0 {
|
if file.Size <= 0 {
|
||||||
return "", errors.New("file size must be greater than zero")
|
return "", errors.New("file size must be greater than zero")
|
||||||
}
|
}
|
||||||
return c.TarUpload(manifest, &FileUploader{file})
|
return c.TarUpload(manifest, &FileUploader{file}, toEncrypt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download downloads a file with the given path from the swarm manifest with
|
// Download downloads a file with the given path from the swarm manifest with
|
||||||
|
|
@ -159,14 +166,14 @@ func (c *Client) Download(hash, path string) (*File, error) {
|
||||||
// directory will then be available at bzz:/<hash>/path/to/file), with
|
// directory will then be available at bzz:/<hash>/path/to/file), with
|
||||||
// the file specified in defaultPath being uploaded to the root of the manifest
|
// the file specified in defaultPath being uploaded to the root of the manifest
|
||||||
// (i.e. bzz:/<hash>/)
|
// (i.e. bzz:/<hash>/)
|
||||||
func (c *Client) UploadDirectory(dir, defaultPath, manifest string) (string, error) {
|
func (c *Client) UploadDirectory(dir, defaultPath, manifest string, toEncrypt bool) (string, error) {
|
||||||
stat, err := os.Stat(dir)
|
stat, err := os.Stat(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
} else if !stat.IsDir() {
|
} else if !stat.IsDir() {
|
||||||
return "", fmt.Errorf("not a directory: %s", dir)
|
return "", fmt.Errorf("not a directory: %s", dir)
|
||||||
}
|
}
|
||||||
return c.TarUpload(manifest, &DirectoryUploader{dir, defaultPath})
|
return c.TarUpload(manifest, &DirectoryUploader{dir, defaultPath}, toEncrypt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadDirectory downloads the files contained in a swarm manifest under
|
// DownloadDirectory downloads the files contained in a swarm manifest under
|
||||||
|
|
@ -229,26 +236,26 @@ func (c *Client) DownloadDirectory(hash, path, destDir string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadManifest uploads the given manifest to swarm
|
// UploadManifest uploads the given manifest to swarm
|
||||||
func (c *Client) UploadManifest(m *api.Manifest) (string, error) {
|
func (c *Client) UploadManifest(m *api.Manifest, toEncrypt bool) (string, error) {
|
||||||
data, err := json.Marshal(m)
|
data, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return c.UploadRaw(bytes.NewReader(data), int64(len(data)))
|
return c.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadManifest downloads a swarm manifest
|
// DownloadManifest downloads a swarm manifest
|
||||||
func (c *Client) DownloadManifest(hash string) (*api.Manifest, error) {
|
func (c *Client) DownloadManifest(hash string) (*api.Manifest, bool, error) {
|
||||||
res, err := c.DownloadRaw(hash)
|
res, isEncrypted, err := c.DownloadRaw(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, isEncrypted, err
|
||||||
}
|
}
|
||||||
defer res.Close()
|
defer res.Close()
|
||||||
var manifest api.Manifest
|
var manifest api.Manifest
|
||||||
if err := json.NewDecoder(res).Decode(&manifest); err != nil {
|
if err := json.NewDecoder(res).Decode(&manifest); err != nil {
|
||||||
return nil, err
|
return nil, isEncrypted, err
|
||||||
}
|
}
|
||||||
return &manifest, nil
|
return &manifest, isEncrypted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list files in a swarm manifest which have the given prefix, grouping
|
// List list files in a swarm manifest which have the given prefix, grouping
|
||||||
|
|
@ -350,10 +357,19 @@ type UploadFn func(file *File) error
|
||||||
|
|
||||||
// TarUpload uses the given Uploader to upload files to swarm as a tar stream,
|
// TarUpload uses the given Uploader to upload files to swarm as a tar stream,
|
||||||
// returning the resulting manifest hash
|
// returning the resulting manifest hash
|
||||||
func (c *Client) TarUpload(hash string, uploader Uploader) (string, error) {
|
func (c *Client) TarUpload(hash string, uploader Uploader, toEncrypt bool) (string, error) {
|
||||||
reqR, reqW := io.Pipe()
|
reqR, reqW := io.Pipe()
|
||||||
defer reqR.Close()
|
defer reqR.Close()
|
||||||
req, err := http.NewRequest("POST", c.Gateway+"/bzz:/"+hash, reqR)
|
addr := hash
|
||||||
|
|
||||||
|
// If there is a hash already (a manifest), then that manifest will determine if the upload has
|
||||||
|
// to be encrypted or not. If there is no manifest then the toEncrypt parameter decides if
|
||||||
|
// there is encryption or not.
|
||||||
|
if hash == "" && toEncrypt {
|
||||||
|
// This is the built-in address for the encrypted upload endpoint
|
||||||
|
addr = "encrypt"
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST", c.Gateway+"/bzz:/"+addr, reqR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,13 @@ import (
|
||||||
|
|
||||||
// TestClientUploadDownloadRaw test uploading and downloading raw data to swarm
|
// TestClientUploadDownloadRaw test uploading and downloading raw data to swarm
|
||||||
func TestClientUploadDownloadRaw(t *testing.T) {
|
func TestClientUploadDownloadRaw(t *testing.T) {
|
||||||
|
testClientUploadDownloadRaw(false, t)
|
||||||
|
}
|
||||||
|
func TestClientUploadDownloadRawEncrypted(t *testing.T) {
|
||||||
|
testClientUploadDownloadRaw(true, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testClientUploadDownloadRaw(toEncrypt bool, t *testing.T) {
|
||||||
srv := testutil.NewTestSwarmServer(t)
|
srv := testutil.NewTestSwarmServer(t)
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
||||||
|
|
@ -38,16 +45,19 @@ func TestClientUploadDownloadRaw(t *testing.T) {
|
||||||
|
|
||||||
// upload some raw data
|
// upload some raw data
|
||||||
data := []byte("foo123")
|
data := []byte("foo123")
|
||||||
hash, err := client.UploadRaw(bytes.NewReader(data), int64(len(data)))
|
hash, err := client.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check we can download the same data
|
// check we can download the same data
|
||||||
res, err := client.DownloadRaw(hash)
|
res, isEncrypted, err := client.DownloadRaw(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if isEncrypted != toEncrypt {
|
||||||
|
t.Fatalf("Expected encyption status %v got %v", toEncrypt, isEncrypted)
|
||||||
|
}
|
||||||
defer res.Close()
|
defer res.Close()
|
||||||
gotData, err := ioutil.ReadAll(res)
|
gotData, err := ioutil.ReadAll(res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -61,6 +71,14 @@ func TestClientUploadDownloadRaw(t *testing.T) {
|
||||||
// TestClientUploadDownloadFiles test uploading and downloading files to swarm
|
// TestClientUploadDownloadFiles test uploading and downloading files to swarm
|
||||||
// manifests
|
// manifests
|
||||||
func TestClientUploadDownloadFiles(t *testing.T) {
|
func TestClientUploadDownloadFiles(t *testing.T) {
|
||||||
|
testClientUploadDownloadFiles(false, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientUploadDownloadFilesEncrypted(t *testing.T) {
|
||||||
|
testClientUploadDownloadFiles(true, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testClientUploadDownloadFiles(toEncrypt bool, t *testing.T) {
|
||||||
srv := testutil.NewTestSwarmServer(t)
|
srv := testutil.NewTestSwarmServer(t)
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
||||||
|
|
@ -74,7 +92,7 @@ func TestClientUploadDownloadFiles(t *testing.T) {
|
||||||
Size: int64(len(data)),
|
Size: int64(len(data)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
hash, err := client.Upload(file, manifest)
|
hash, err := client.Upload(file, manifest, toEncrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +186,7 @@ func TestClientUploadDownloadDirectory(t *testing.T) {
|
||||||
// upload the directory
|
// upload the directory
|
||||||
client := NewClient(srv.URL)
|
client := NewClient(srv.URL)
|
||||||
defaultPath := filepath.Join(dir, testDirFiles[0])
|
defaultPath := filepath.Join(dir, testDirFiles[0])
|
||||||
hash, err := client.UploadDirectory(dir, defaultPath, "")
|
hash, err := client.UploadDirectory(dir, defaultPath, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error uploading directory: %s", err)
|
t.Fatalf("error uploading directory: %s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -217,6 +235,14 @@ func TestClientUploadDownloadDirectory(t *testing.T) {
|
||||||
|
|
||||||
// TestClientFileList tests listing files in a swarm manifest
|
// TestClientFileList tests listing files in a swarm manifest
|
||||||
func TestClientFileList(t *testing.T) {
|
func TestClientFileList(t *testing.T) {
|
||||||
|
testClientFileList(false, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientFileListEncrypted(t *testing.T) {
|
||||||
|
testClientFileList(true, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testClientFileList(toEncrypt bool, t *testing.T) {
|
||||||
srv := testutil.NewTestSwarmServer(t)
|
srv := testutil.NewTestSwarmServer(t)
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
||||||
|
|
@ -224,7 +250,7 @@ func TestClientFileList(t *testing.T) {
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
client := NewClient(srv.URL)
|
client := NewClient(srv.URL)
|
||||||
hash, err := client.UploadDirectory(dir, "", "")
|
hash, err := client.UploadDirectory(dir, "", "", toEncrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error uploading directory: %s", err)
|
t.Fatalf("error uploading directory: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,7 @@ func retrieveToFile(quitC chan bool, dpa *storage.DPA, key storage.Key, path str
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
reader := dpa.Retrieve(key)
|
reader, _ := dpa.Retrieve(key)
|
||||||
writer := bufio.NewWriter(f)
|
writer := bufio.NewWriter(f)
|
||||||
size, err := reader.Size(quitC)
|
size, err := reader.Size(quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -556,13 +556,15 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the root chunk exists by retrieving the file's size
|
// check the root chunk exists by retrieving the file's size
|
||||||
reader := s.api.Retrieve(key)
|
reader, isEncrypted := s.api.Retrieve(key)
|
||||||
if _, err := reader.Size(nil); err != nil {
|
if _, err := reader.Size(nil); err != nil {
|
||||||
getFail.Inc(1)
|
getFail.Inc(1)
|
||||||
Respond(w, r, fmt.Sprintf("root chunk not found %s: %s", key, err), http.StatusNotFound)
|
Respond(w, r, fmt.Sprintf("root chunk not found %s: %s", key, err), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Set("X-Decrypted", fmt.Sprintf("%v", isEncrypted))
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case r.uri.Raw() || r.uri.DeprecatedRaw():
|
case r.uri.Raw() || r.uri.DeprecatedRaw():
|
||||||
// allow the request to overwrite the content type using a query
|
// allow the request to overwrite the content type using a query
|
||||||
|
|
@ -619,11 +621,12 @@ func (s *Server) HandleGetFiles(w http.ResponseWriter, r *Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve the entry's key and size
|
// retrieve the entry's key and size
|
||||||
reader := s.api.Retrieve(storage.Key(common.Hex2Bytes(entry.Hash)))
|
reader, isEncrypted := s.api.Retrieve(storage.Key(common.Hex2Bytes(entry.Hash)))
|
||||||
size, err := reader.Size(nil)
|
size, err := reader.Size(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
w.Header().Set("X-Decrypted", fmt.Sprintf("%v", isEncrypted))
|
||||||
|
|
||||||
// write a tar header for the entry
|
// write a tar header for the entry
|
||||||
hdr := &tar.Header{
|
hdr := &tar.Header{
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,6 @@ func testBzzGetPath(encrypted bool, t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
wait()
|
wait()
|
||||||
fmt.Println("!!!!!!!!!!", i, key[i])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rootRef := key[2].Hex()
|
rootRef := key[2].Hex()
|
||||||
|
|
@ -458,6 +457,13 @@ func testBzzGetPath(encrypted bool, t *testing.T) {
|
||||||
// a trailing slash gets redirected to include the trailing slash so that
|
// a trailing slash gets redirected to include the trailing slash so that
|
||||||
// relative URLs work as expected.
|
// relative URLs work as expected.
|
||||||
func TestBzzRootRedirect(t *testing.T) {
|
func TestBzzRootRedirect(t *testing.T) {
|
||||||
|
testBzzRootRedirect(false, t)
|
||||||
|
}
|
||||||
|
func TestBzzRootRedirectEncrypted(t *testing.T) {
|
||||||
|
testBzzRootRedirect(true, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testBzzRootRedirect(toEncrypt bool, t *testing.T) {
|
||||||
srv := testutil.NewTestSwarmServer(t)
|
srv := testutil.NewTestSwarmServer(t)
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
||||||
|
|
@ -472,7 +478,7 @@ func TestBzzRootRedirect(t *testing.T) {
|
||||||
Size: int64(len(data)),
|
Size: int64(len(data)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
hash, err := client.Upload(file, "")
|
hash, err := client.Upload(file, "", toEncrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -205,12 +205,12 @@ type manifestTrieEntry struct {
|
||||||
func loadManifest(dpa *storage.DPA, hash storage.Key, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand
|
func loadManifest(dpa *storage.DPA, hash storage.Key, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand
|
||||||
log.Trace("manifest lookup", "key", hash)
|
log.Trace("manifest lookup", "key", hash)
|
||||||
// retrieve manifest via DPA
|
// retrieve manifest via DPA
|
||||||
manifestReader := dpa.Retrieve(hash)
|
manifestReader, isEncrypted := dpa.Retrieve(hash)
|
||||||
log.Trace("reader retrieved", "key", hash)
|
log.Trace("reader retrieved", "key", hash)
|
||||||
return readManifest(manifestReader, hash, dpa, quitC)
|
return readManifest(manifestReader, hash, dpa, isEncrypted, quitC)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readManifest(manifestReader storage.LazySectionReader, hash storage.Key, dpa *storage.DPA, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand
|
func readManifest(manifestReader storage.LazySectionReader, hash storage.Key, dpa *storage.DPA, isEncrypted bool, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand
|
||||||
|
|
||||||
// TODO check size for oversized manifests
|
// TODO check size for oversized manifests
|
||||||
size, err := manifestReader.Size(quitC)
|
size, err := manifestReader.Size(quitC)
|
||||||
|
|
@ -245,7 +245,7 @@ func readManifest(manifestReader storage.LazySectionReader, hash storage.Key, dp
|
||||||
|
|
||||||
trie = &manifestTrie{
|
trie = &manifestTrie{
|
||||||
dpa: dpa,
|
dpa: dpa,
|
||||||
encrypted: (len(hash) > dpa.HashSize()),
|
encrypted: isEncrypted,
|
||||||
}
|
}
|
||||||
for _, entry := range man.Entries {
|
for _, entry := range man.Entries {
|
||||||
trie.addEntry(entry, quitC)
|
trie.addEntry(entry, quitC)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ func testGetEntry(t *testing.T, path, match string, multiple bool, paths ...stri
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
dpa := storage.NewDPA(nil, storage.NewDPAParams())
|
dpa := storage.NewDPA(nil, storage.NewDPAParams())
|
||||||
ref := make([]byte, dpa.HashSize())
|
ref := make([]byte, dpa.HashSize())
|
||||||
trie, err := readManifest(manifest(paths...), ref, dpa, quitC)
|
trie, err := readManifest(manifest(paths...), ref, dpa, false, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error making manifest: %v", err)
|
t.Errorf("unexpected error making manifest: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -101,7 +101,7 @@ func TestExactMatch(t *testing.T) {
|
||||||
mf := manifest("shouldBeExactMatch.css", "shouldBeExactMatch.css.map")
|
mf := manifest("shouldBeExactMatch.css", "shouldBeExactMatch.css.map")
|
||||||
dpa := storage.NewDPA(nil, storage.NewDPAParams())
|
dpa := storage.NewDPA(nil, storage.NewDPAParams())
|
||||||
ref := make([]byte, dpa.HashSize())
|
ref := make([]byte, dpa.HashSize())
|
||||||
trie, err := readManifest(mf, ref, dpa, quitC)
|
trie, err := readManifest(mf, ref, dpa, false, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error making manifest: %v", err)
|
t.Errorf("unexpected error making manifest: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -134,7 +134,7 @@ func TestAddFileWithManifestPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
dpa := storage.NewDPA(nil, storage.NewDPAParams())
|
dpa := storage.NewDPA(nil, storage.NewDPAParams())
|
||||||
ref := make([]byte, dpa.HashSize())
|
ref := make([]byte, dpa.HashSize())
|
||||||
trie, err := readManifest(reader, ref, dpa, nil)
|
trie, err := readManifest(reader, ref, dpa, false, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ func (file *SwarmFile) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
a.Gid = uint32(os.Getegid())
|
a.Gid = uint32(os.Getegid())
|
||||||
|
|
||||||
if file.fileSize == -1 {
|
if file.fileSize == -1 {
|
||||||
reader := file.mountInfo.swarmApi.Retrieve(file.key)
|
reader, _ := file.mountInfo.swarmApi.Retrieve(file.key)
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
size, err := reader.Size(quitC)
|
size, err := reader.Size(quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -99,7 +99,7 @@ func (sf *SwarmFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse
|
||||||
sf.lock.RLock()
|
sf.lock.RLock()
|
||||||
defer sf.lock.RUnlock()
|
defer sf.lock.RUnlock()
|
||||||
if sf.reader == nil {
|
if sf.reader == nil {
|
||||||
sf.reader = sf.mountInfo.swarmApi.Retrieve(sf.key)
|
sf.reader, _ = sf.mountInfo.swarmApi.Retrieve(sf.key)
|
||||||
}
|
}
|
||||||
buf := make([]byte, req.Size)
|
buf := make([]byte, req.Size)
|
||||||
n, err := sf.reader.ReadAt(buf, req.Offset)
|
n, err := sf.reader.ReadAt(buf, req.Offset)
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,7 @@ func (r *TestRegistry) APIs() []rpc.API {
|
||||||
}
|
}
|
||||||
|
|
||||||
func readAll(dpa *storage.DPA, hash []byte) (int64, error) {
|
func readAll(dpa *storage.DPA, hash []byte) (int64, error) {
|
||||||
r := dpa.Retrieve(hash)
|
r, _ := dpa.Retrieve(hash)
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
var n int
|
var n int
|
||||||
var total int64
|
var total int64
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,12 @@ func NewDPA(store ChunkStore, params *DPAParams) *DPA {
|
||||||
// FS-aware API and httpaccess
|
// FS-aware API and httpaccess
|
||||||
// Chunk retrieval blocks on netStore requests with a timeout so reader will
|
// Chunk retrieval blocks on netStore requests with a timeout so reader will
|
||||||
// report error if retrieval of chunks within requested range time out.
|
// report error if retrieval of chunks within requested range time out.
|
||||||
func (self *DPA) Retrieve(key Key) LazySectionReader {
|
// It returns a reader with the chunk data and whether the content was encrypted
|
||||||
getter := NewHasherStore(self.ChunkStore, self.hashFunc, len(key) > self.hashFunc().Size())
|
func (self *DPA) Retrieve(key Key) (reader LazySectionReader, isEncrypted bool) {
|
||||||
return TreeJoin(key, getter, 0)
|
isEncrypted = len(key) > self.hashFunc().Size()
|
||||||
|
getter := NewHasherStore(self.ChunkStore, self.hashFunc, isEncrypted)
|
||||||
|
reader = TreeJoin(key, getter, 0)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public API. Main entry point for document storage directly. Used by the
|
// Public API. Main entry point for document storage directly. Used by the
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,10 @@ func testDpaRandom(toEncrypt bool, t *testing.T) {
|
||||||
t.Errorf("Store error: %v", err)
|
t.Errorf("Store error: %v", err)
|
||||||
}
|
}
|
||||||
wait()
|
wait()
|
||||||
resultReader := dpa.Retrieve(key)
|
resultReader, isEncrypted := dpa.Retrieve(key)
|
||||||
|
if isEncrypted != toEncrypt {
|
||||||
|
t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted)
|
||||||
|
}
|
||||||
resultSlice := make([]byte, len(slice))
|
resultSlice := make([]byte, len(slice))
|
||||||
n, err := resultReader.ReadAt(resultSlice, 0)
|
n, err := resultReader.ReadAt(resultSlice, 0)
|
||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
|
|
@ -69,7 +72,10 @@ func testDpaRandom(toEncrypt bool, t *testing.T) {
|
||||||
ioutil.WriteFile("/tmp/slice.bzz.16M", slice, 0666)
|
ioutil.WriteFile("/tmp/slice.bzz.16M", slice, 0666)
|
||||||
ioutil.WriteFile("/tmp/result.bzz.16M", resultSlice, 0666)
|
ioutil.WriteFile("/tmp/result.bzz.16M", resultSlice, 0666)
|
||||||
localStore.memStore = NewMemStore(db, defaultCacheCapacity)
|
localStore.memStore = NewMemStore(db, defaultCacheCapacity)
|
||||||
resultReader = dpa.Retrieve(key)
|
resultReader, isEncrypted = dpa.Retrieve(key)
|
||||||
|
if isEncrypted != toEncrypt {
|
||||||
|
t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted)
|
||||||
|
}
|
||||||
for i := range resultSlice {
|
for i := range resultSlice {
|
||||||
resultSlice[i] = 0
|
resultSlice[i] = 0
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +115,10 @@ func testDPA_capacity(toEncrypt bool, t *testing.T) {
|
||||||
t.Errorf("Store error: %v", err)
|
t.Errorf("Store error: %v", err)
|
||||||
}
|
}
|
||||||
wait()
|
wait()
|
||||||
resultReader := dpa.Retrieve(key)
|
resultReader, isEncrypted := dpa.Retrieve(key)
|
||||||
|
if isEncrypted != toEncrypt {
|
||||||
|
t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted)
|
||||||
|
}
|
||||||
resultSlice := make([]byte, len(slice))
|
resultSlice := make([]byte, len(slice))
|
||||||
n, err := resultReader.ReadAt(resultSlice, 0)
|
n, err := resultReader.ReadAt(resultSlice, 0)
|
||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
|
|
@ -125,14 +134,20 @@ func testDPA_capacity(toEncrypt bool, t *testing.T) {
|
||||||
memStore.setCapacity(0)
|
memStore.setCapacity(0)
|
||||||
// check whether it is, indeed, empty
|
// check whether it is, indeed, empty
|
||||||
dpa.ChunkStore = memStore
|
dpa.ChunkStore = memStore
|
||||||
resultReader = dpa.Retrieve(key)
|
resultReader, isEncrypted = dpa.Retrieve(key)
|
||||||
|
if isEncrypted != toEncrypt {
|
||||||
|
t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted)
|
||||||
|
}
|
||||||
if _, err = resultReader.ReadAt(resultSlice, 0); err == nil {
|
if _, err = resultReader.ReadAt(resultSlice, 0); err == nil {
|
||||||
t.Errorf("Was able to read %d bytes from an empty memStore.", len(slice))
|
t.Errorf("Was able to read %d bytes from an empty memStore.", len(slice))
|
||||||
}
|
}
|
||||||
// check how it works with localStore
|
// check how it works with localStore
|
||||||
dpa.ChunkStore = localStore
|
dpa.ChunkStore = localStore
|
||||||
// localStore.dbStore.setCapacity(0)
|
// localStore.dbStore.setCapacity(0)
|
||||||
resultReader = dpa.Retrieve(key)
|
resultReader, isEncrypted = dpa.Retrieve(key)
|
||||||
|
if isEncrypted != toEncrypt {
|
||||||
|
t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted)
|
||||||
|
}
|
||||||
for i := range resultSlice {
|
for i := range resultSlice {
|
||||||
resultSlice[i] = 0
|
resultSlice[i] = 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue