summaryrefslogtreecommitdiffstats
path: root/tools/hole
diff options
context:
space:
mode:
Diffstat (limited to 'tools/hole')
-rw-r--r--tools/hole/hole.go94
1 files changed, 66 insertions, 28 deletions
diff --git a/tools/hole/hole.go b/tools/hole/hole.go
index d701c40..c6946f0 100644
--- a/tools/hole/hole.go
+++ b/tools/hole/hole.go
@@ -1,36 +1,54 @@
+// The hole command is a CLI uploader tool for the roseh.moe wormhole.
+//
+// # Magic wormhole
+//
+// The name is inspired by the original "magic wormhole" library. The goal is to
+// get a file from one computer to another without a USB stick, Including cases
+// where scp might not be available. This includes transferring files to your
+// phone, for example, although a USB cord might still be more convenient when
+// moving many files. It should also work over restrictive firewalls. You should
+// be able to use the wormhole as long as you can access http://roseh.moe in
+// a browser.
+//
+// # Usage example
+//
+// The following shows a typical interaction with the tool
+//
+// $ hole file.pdf
+// https://roseh.moe/wormhole/dv-32-ethos-aztec-shako-spoils-2y-dwarf-sand-any
+// Waiting for upload...
+// <tool hangs, waiting to upload the file>
+//
+// Then, on another machine:
+//
+// $ curl https://roseh.moe/wormhole/dv-32-ethos-aztec-shako-spoils-2y-dwarf-sand-any > file.pdf
+//
+// # Web interface
+//
+// There's also a web interface available for the wormhole, available at
+// https://roseh.moe/wormhole.
package main
import (
- "crypto/rand"
- "encoding/binary"
"flag"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
- "strings"
- "gitlab.com/rhogenson/roseh.moe/internal/wordlist"
+ "gitlab.com/rhogenson/roseh.moe/internal/hole"
)
var url = flag.String("url", "https://roseh.moe", "server URL")
-func makeHole() string {
- const nWords = 10
- buf := make([]byte, 2*nWords)
- rand.Read(buf)
- words := make([]string, nWords)
- for i := range words {
- words[i] = wordlist.Words[binary.NativeEndian.Uint16(buf[2*i:])&0x1fff]
- }
- return strings.Join(words, "-")
-}
-
-func hole() error {
+func upload() error {
args := flag.Args()
- if len(args) != 1 {
- return fmt.Errorf("usage error")
+ if len(args) == 0 {
+ return fmt.Errorf("usage error: missing filename")
+ }
+ if len(args) > 1 {
+ return fmt.Errorf("usage error: too many positional arguments")
}
fileName := args[0]
f, err := os.Open(fileName)
@@ -38,18 +56,19 @@ func hole() error {
return err
}
defer f.Close()
- hole := makeHole()
+ hole := hole.New()
fmt.Println(*url + "/wormhole/" + hole)
+ fmt.Fprintln(os.Stderr, "Waiting for upload...")
resp, err := http.Get(*url + "/wormhole/" + hole + "/ready")
if err != nil {
- return err
+ return fmt.Errorf("check wormhole ready: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("%s", resp.Status)
+ return fmt.Errorf("check wormhole ready: status: %s", resp.Status)
}
if _, err := io.Copy(io.Discard, resp.Body); err != nil {
- return err
+ return fmt.Errorf("check wormhole ready: read response: %s", err)
}
pipeReader, pipeWriter := io.Pipe()
multipartWriter := multipart.NewWriter(pipeWriter)
@@ -57,15 +76,15 @@ func hole() error {
defer pipeWriter.Close()
part, err := multipartWriter.CreateFormFile("file", fileName)
if err != nil {
- fmt.Fprintln(os.Stderr, err)
+ pipeWriter.CloseWithError(fmt.Errorf("create multipart reader: %s", err))
return
}
if _, err := io.Copy(part, f); err != nil {
- fmt.Fprintln(os.Stderr, err)
+ pipeWriter.CloseWithError(fmt.Errorf("write body: %s", err))
return
}
if err := multipartWriter.Close(); err != nil {
- fmt.Fprintln(os.Stderr, err)
+ pipeWriter.CloseWithError(fmt.Errorf("write trailer: %s", err))
return
}
}()
@@ -75,7 +94,7 @@ func hole() error {
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("%s", resp.Status)
+ return fmt.Errorf("upload: status: %s", resp.Status)
}
io.Copy(os.Stderr, resp.Body)
fmt.Fprintln(os.Stderr)
@@ -83,9 +102,28 @@ func hole() error {
}
func main() {
+ flag.Usage = func() {
+ fmt.Fprint(os.Stderr, `Usage: hole FILE
+Create a one-time wormhole that allows a specific client to download a
+file. Prints the URL to download the file and then hangs until the file
+is downloaded.
+
+Example:
+ $ hole file.pdf
+ https://roseh.moe/wormhole/dv-32-ethos-aztec-shako-spoils-2y-dwarf-sand-any
+ Waiting for upload...
+ <tool hangs, waiting to upload the file>
+
+Then, on another machine:
+ $ curl https://roseh.moe/wormhole/dv-32-ethos-aztec-shako-spoils-2y-dwarf-sand-any > file.pdf
+
+Flags:
+`)
+ flag.PrintDefaults()
+ }
flag.Parse()
- if err := hole(); err != nil {
- fmt.Fprintln(os.Stderr, err)
+ if err := upload(); err != nil {
+ fmt.Fprintf(os.Stderr, "hole: %s\n", err)
os.Exit(1)
}
}