]> Cypherpunks.ru repositories - nncp.git/commitdiff
Ability to read the data from stdin for nncp-file
authorSergey Matveev <stargrave@stargrave.org>
Fri, 28 Apr 2017 10:31:16 +0000 (13:31 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Fri, 28 Apr 2017 10:32:45 +0000 (13:32 +0300)
doc/cmds.texi
src/cypherpunks.ru/nncp/cmd/nncp-file/main.go
src/cypherpunks.ru/nncp/tx.go

index 4fa10456e5430e39b0b7b42a0434bdee076c40c5..70586a7aa8d731acf46d58ec09fd9da8ee0352e8 100644 (file)
@@ -125,6 +125,12 @@ This command queues file in @ref{Spool, spool} directory immediately
 (through the temporary file of course) -- so pay attention that sending
 2 GiB file will create 2 GiB outbound encrypted packet.
 
+If @file{SRC} equals to @file{-}, then create an encrypted temporary
+file and copy everything taken from stdin to it and use for outbound
+packet creation. Pay attention that if you want to send 1 GiB of data
+taken from stdin, then you have to have 2 GiB of disk space for that
+temporary file and resulting encrypted packet.
+
 If @ref{CfgNotify, notification} is enabled on the remote side for
 file transmissions, then it will sent simple letter after successful
 file receiving.
index 824cdb0a2a7820308a4e4b404d8276bbc808d906..7256bcf5ee9e453bac886658706c50bdc3d62954 100644 (file)
@@ -35,6 +35,9 @@ func usage() {
        fmt.Fprintln(os.Stderr, "nncp-file -- send file\n")
        fmt.Fprintf(os.Stderr, "Usage: %s [options] SRC NODE:[DST]\nOptions:\n", os.Args[0])
        flag.PrintDefaults()
+       fmt.Fprint(os.Stderr, `
+If SRC equals to -, then read data from stdin to temporary file.
+`)
 }
 
 func main() {
index a04f5bdb2dadaaf59012b3ab54939d14bfaff95c..2c9bd07ba790a6e91573e13566fb2af5e66b6086 100644 (file)
@@ -22,9 +22,12 @@ import (
        "bufio"
        "bytes"
        "compress/zlib"
+       "crypto/cipher"
+       "crypto/rand"
        "errors"
        "hash"
        "io"
+       "io/ioutil"
        "os"
        "path/filepath"
        "strconv"
@@ -32,6 +35,7 @@ import (
 
        "github.com/davecgh/go-xdr/xdr2"
        "golang.org/x/crypto/blake2b"
+       "golang.org/x/crypto/twofish"
 )
 
 func (ctx *Ctx) Tx(node *Node, pkt *Pkt, nice uint8, size, minSize int64, src io.Reader) (*Node, error) {
@@ -103,8 +107,57 @@ func (ctx *Ctx) Tx(node *Node, pkt *Pkt, nice uint8, size, minSize int64, src io
        return lastNode, err
 }
 
+func prepareTxFile(srcPath string) (io.Reader, *os.File, int64, error) {
+       var reader io.Reader
+       var src *os.File
+       var fileSize int64
+       var err error
+       if srcPath == "-" {
+               src, err = ioutil.TempFile("", "nncp-file")
+               if err != nil {
+                       return nil, nil, 0, err
+               }
+               os.Remove(src.Name())
+               tmpW := bufio.NewWriter(src)
+
+               tmpKey := make([]byte, 32)
+               if _, err = rand.Read(tmpKey); err != nil {
+                       return nil, nil, 0, err
+               }
+               ciph, err := twofish.NewCipher(tmpKey)
+               if err != nil {
+                       return nil, nil, 0, err
+               }
+               ctr := cipher.NewCTR(ciph, make([]byte, twofish.BlockSize))
+               encrypter := &cipher.StreamWriter{S: ctr, W: tmpW}
+               fileSize, err = io.Copy(encrypter, bufio.NewReader(os.Stdin))
+               if err != nil {
+                       return nil, nil, 0, err
+               }
+               tmpW.Flush()
+               src.Seek(0, 0)
+               ctr = cipher.NewCTR(ciph, make([]byte, twofish.BlockSize))
+               reader = &cipher.StreamReader{S: ctr, R: bufio.NewReader(src)}
+       } else {
+               src, err = os.Open(srcPath)
+               if err != nil {
+                       return nil, nil, 0, err
+               }
+               srcStat, err := src.Stat()
+               if err != nil {
+                       return nil, nil, 0, err
+               }
+               fileSize = srcStat.Size()
+               reader = bufio.NewReader(src)
+       }
+       return reader, src, fileSize, nil
+}
+
 func (ctx *Ctx) TxFile(node *Node, nice uint8, srcPath, dstPath string, minSize int64) error {
        if dstPath == "" {
+               if srcPath == "-" {
+                       return errors.New("Must provide destination filename")
+               }
                dstPath = filepath.Base(srcPath)
        }
        dstPath = filepath.Clean(dstPath)
@@ -115,16 +168,14 @@ func (ctx *Ctx) TxFile(node *Node, nice uint8, srcPath, dstPath string, minSize
        if err != nil {
                return err
        }
-       src, err := os.Open(srcPath)
-       if err != nil {
-               return err
+       reader, src, fileSize, err := prepareTxFile(srcPath)
+       if src != nil {
+               defer src.Close()
        }
-       defer src.Close()
-       srcStat, err := src.Stat()
        if err != nil {
                return err
        }
-       _, err = ctx.Tx(node, pkt, nice, srcStat.Size(), minSize, bufio.NewReader(src))
+       _, err = ctx.Tx(node, pkt, nice, fileSize, minSize, reader)
        if err == nil {
                ctx.LogI("tx", SDS{
                        "type": "file",
@@ -132,7 +183,7 @@ func (ctx *Ctx) TxFile(node *Node, nice uint8, srcPath, dstPath string, minSize
                        "nice": strconv.Itoa(int(nice)),
                        "src":  srcPath,
                        "dst":  dstPath,
-                       "size": strconv.FormatInt(srcStat.Size(), 10),
+                       "size": strconv.FormatInt(fileSize, 10),
                }, "sent")
        } else {
                ctx.LogE("tx", SDS{
@@ -141,7 +192,7 @@ func (ctx *Ctx) TxFile(node *Node, nice uint8, srcPath, dstPath string, minSize
                        "nice": strconv.Itoa(int(nice)),
                        "src":  srcPath,
                        "dst":  dstPath,
-                       "size": strconv.FormatInt(srcStat.Size(), 10),
+                       "size": strconv.FormatInt(fileSize, 10),
                        "err":  err,
                }, "sent")
        }
@@ -150,23 +201,23 @@ func (ctx *Ctx) TxFile(node *Node, nice uint8, srcPath, dstPath string, minSize
 
 func (ctx *Ctx) TxFileChunked(node *Node, nice uint8, srcPath, dstPath string, minSize int64, chunkSize int64) error {
        if dstPath == "" {
+               if srcPath == "-" {
+                       return errors.New("Must provide destination filename")
+               }
                dstPath = filepath.Base(srcPath)
        }
        dstPath = filepath.Clean(dstPath)
        if filepath.IsAbs(dstPath) {
                return errors.New("Relative destination path required")
        }
-       src, err := os.Open(srcPath)
-       if err != nil {
-               return err
+       reader, src, fileSize, err := prepareTxFile(srcPath)
+       if src != nil {
+               defer src.Close()
        }
-       defer src.Close()
-       srcStat, err := src.Stat()
        if err != nil {
                return err
        }
-       srcReader := bufio.NewReader(src)
-       fileSize := srcStat.Size()
+
        leftSize := fileSize
        metaPkt := ChunkedMeta{
                Magic:     MagicNNCPMv1,
@@ -204,7 +255,7 @@ func (ctx *Ctx) TxFileChunked(node *Node, nice uint8, srcPath, dstPath string, m
                        nice,
                        sizeToSend,
                        minSize,
-                       io.TeeReader(srcReader, hsh),
+                       io.TeeReader(reader, hsh),
                )
                if err == nil {
                        ctx.LogD("tx", SDS{