cmd/swarm, swarm/api: Swarm command line api to upload encrypted files

This commit is contained in:
Balint Gabor 2018-04-09 23:52:13 +02:00
parent f6d48fe564
commit 3d1a1aa459
4 changed files with 57 additions and 14 deletions

View file

@ -218,12 +218,21 @@ The output of this command is supposed to be machine-readable.
`,
},
{
Action: upload,
Action: nonEncryptedUpload,
Name: "up",
Usage: "upload a file or directory to swarm using the HTTP API",
ArgsUsage: " <file>",
Description: `
"upload a file or directory to swarm using the HTTP API and prints the root hash",
`,
},
{
Action: encryptedUpload,
Name: "encrypted-up",
Usage: "Upload a file or directory with encryption to swarm using the HTTP API. NOTE: Currently the reference for the uploaded content is non-deterministic, so you will receive different references if you upload it twice.",
ArgsUsage: " <file>",
Description: `
"upload a file or directory to swarm using the HTTP API and prints the root hash",
`,
},
{

View file

@ -35,7 +35,15 @@ import (
"gopkg.in/urfave/cli.v1"
)
func upload(ctx *cli.Context) {
func encryptedUpload(ctx *cli.Context) {
upload(ctx, true)
}
func nonEncryptedUpload(ctx *cli.Context) {
upload(ctx, false)
}
func upload(ctx *cli.Context, toEncrypt bool) {
args := ctx.Args()
var (
@ -97,7 +105,7 @@ func upload(ctx *cli.Context) {
if !recursive {
return "", errors.New("Argument is a directory and recursive upload is disabled")
}
return client.UploadDirectory(file, defaultPath, "")
return client.UploadDirectory(file, defaultPath, "", toEncrypt)
}
} else {
doUpload = func() (string, error) {
@ -110,7 +118,7 @@ func upload(ctx *cli.Context) {
mimeType = detectMimeType(file)
}
f.ContentType = mimeType
return client.Upload(f, "")
return client.Upload(f, "", toEncrypt)
}
}
hash, err := doUpload()

View file

@ -17,6 +17,7 @@
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
@ -29,6 +30,16 @@ import (
// TestCLISwarmUp tests that running 'swarm up' makes the resulting file
// available from all nodes via the HTTP API
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")
cluster := newTestCluster(t, 3)
defer cluster.Shutdown()
@ -48,10 +59,16 @@ func TestCLISwarmUp(t *testing.T) {
t.Fatal(err)
}
// upload the file with 'swarm up' and expect a hash
log.Info("uploading file with 'swarm up'")
up := runSwarm(t, "--bzzapi", cluster.Nodes[0].URL, "up", tmp.Name())
_, matches := up.ExpectRegexp(`[a-f\d]{64}`)
cmd := "up"
hashRegexp := `[a-f\d]{64}`
if toEncrypt {
cmd = "encrypted-up"
hashRegexp = `[a-f\d]{128}`
}
// upload the file with 'swarm up' or 'swarm encrypted-up' and expect a hash
log.Info(fmt.Sprintf("uploading file with '%s'", cmd))
up := runSwarm(t, "--bzzapi", cluster.Nodes[0].URL, cmd, tmp.Name())
_, matches := up.ExpectRegexp(hashRegexp)
up.ExpectExit()
hash := matches[0]
log.Info("file uploaded", "hash", hash)

View file

@ -125,11 +125,11 @@ func Open(path string) (*File, error) {
// (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
// 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 {
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
@ -159,14 +159,14 @@ func (c *Client) Download(hash, path string) (*File, error) {
// 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
// (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)
if err != nil {
return "", err
} else if !stat.IsDir() {
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
@ -350,10 +350,19 @@ type UploadFn func(file *File) error
// TarUpload uses the given Uploader to upload files to swarm as a tar stream,
// 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()
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 {
return "", err
}