From c1c8e394991b3bb1c7c38f0621c2c17ca8c84441 Mon Sep 17 00:00:00 2001 From: Zack Scholl Date: Mon, 29 Apr 2019 20:40:42 -0700 Subject: [PATCH] working --- go.mod | 7 +- go.sum | 11 +++ src/croc/croc.go | 209 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 201 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index 868a4b0..3c6c141 100644 --- a/go.mod +++ b/go.mod @@ -4,17 +4,20 @@ require ( github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 github.com/denisbrodbeck/machineid v1.0.1 github.com/fatih/color v1.7.0 // indirect + github.com/google/pprof v0.0.0-20190404155422-f8f10df84213 // indirect github.com/gorilla/websocket v1.4.0 + github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect github.com/mattn/go-colorable v0.1.1 // indirect github.com/mattn/go-isatty v0.0.7 // indirect - github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/pkg/errors v0.8.1 github.com/schollz/mnemonicode v1.0.1 github.com/schollz/pake v1.1.0 - github.com/schollz/progressbar/v2 v2.10.0 + github.com/schollz/progressbar/v2 v2.12.0 github.com/schollz/spinner v0.0.0-20180925172146-6bbc5f7804f9 + github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.3.0 github.com/urfave/cli v1.20.0 + golang.org/x/arch v0.0.0-20190312162104-788fe5ffcd8c // indirect golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/sys v0.0.0-20190312061237-fead79001313 // indirect ) diff --git a/go.sum b/go.sum index 74c7c04..dba7df7 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,12 @@ github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMS github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/google/pprof v0.0.0-20190404155422-f8f10df84213 h1:y77GPNuZbqlt3/OjKA9yysnnxxqW+XwLaGY3ol9Mgmc= +github.com/google/pprof v0.0.0-20190404155422-f8f10df84213/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -28,9 +32,13 @@ github.com/schollz/pake v1.1.0 h1:+tYqsPVkuirFpmeRePjYTUhIHHKLufdmd7QfuspaXCk= github.com/schollz/pake v1.1.0/go.mod h1:pL7Z08gnQ4OQ3G27s5e5T6TEzp6cFc5GzCwLm0f75Io= github.com/schollz/progressbar/v2 v2.10.0 h1:AxYYUjr5fOPlA0Pcqc3R3kDBrqyLFWk2P7LRLdXb3yE= github.com/schollz/progressbar/v2 v2.10.0/go.mod h1:l6tn6yU6ZdQoF8lwX/VoAUQ3FjhCbrcZDnl9xeWZzYw= +github.com/schollz/progressbar/v2 v2.12.0 h1:eTkmx9oWkRqi+rAzSDsreLbwGHvlrLJDR8xzmO0ccDI= +github.com/schollz/progressbar/v2 v2.12.0/go.mod h1:fBI3onORwtNtwCWJHsrXtjE3QnJOtqIZrvr3rDaF7L0= github.com/schollz/spinner v0.0.0-20180925172146-6bbc5f7804f9 h1:y08o5oQ/slxXE/F0uh5dd8mdVvb+w4NLcNSDSq4c2F0= github.com/schollz/spinner v0.0.0-20180925172146-6bbc5f7804f9/go.mod h1:kCMoQsqzx4MzGJWaALr6tKyCnlrY0kILGLkA1FOiLF4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -38,6 +46,8 @@ github.com/tscholl2/siec v0.0.0-20180721101609-21667da05937 h1:lhssCpSe3TjKcbvUo github.com/tscholl2/siec v0.0.0-20180721101609-21667da05937/go.mod h1:KL9+ubr1JZdaKjgAaHr+tCytEncXBa1pR6FjbTsOJnw= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +golang.org/x/arch v0.0.0-20190312162104-788fe5ffcd8c h1:Rx/HTKi09myZ25t1SOlDHmHOy/mKxNAcu0hP1oPX9qM= +golang.org/x/arch v0.0.0-20190312162104-788fe5ffcd8c/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -47,3 +57,4 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjW golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/src/croc/croc.go b/src/croc/croc.go index 55b13e5..9c2ac00 100644 --- a/src/croc/croc.go +++ b/src/croc/croc.go @@ -3,9 +3,11 @@ package croc import ( "bytes" "crypto/elliptic" - "encoding/base64" + "encoding/binary" "encoding/json" "fmt" + "io" + "math" "os" "path" "path/filepath" @@ -17,6 +19,7 @@ import ( "github.com/denisbrodbeck/machineid" "github.com/pkg/errors" "github.com/schollz/croc/v6/src/comm" + "github.com/schollz/croc/v6/src/compress" "github.com/schollz/croc/v6/src/crypt" "github.com/schollz/croc/v6/src/logger" "github.com/schollz/croc/v6/src/message" @@ -254,25 +257,35 @@ func (c *Client) transfer(options TransferOptions) (err error) { // listen for incoming messages and process them for { var data []byte + var done bool data, err = c.conn[0].Receive() if err != nil { return } - err = c.processMessage(data) + done, err = c.processMessage(data) if err != nil { return } + if done { + break + } } return } -func (c *Client) processMessage(payload []byte) (err error) { +func (c *Client) processMessage(payload []byte) (done bool, err error) { m, err := message.Decode(c.Key, payload) if err != nil { return } switch m.Type { + case "finished": + err = message.Send(c.conn[0], c.Key, message.Message{ + Type: "finished", + }) + done = true + return case "pake": // if // c.spinner.Suffix != " performing PAKE..." { // // c.spinner.Stop() @@ -294,11 +307,25 @@ func (c *Client) processMessage(payload []byte) (err error) { log.Debug("session key is verified, generating encryption") key, err := c.Pake.SessionKey() if err != nil { - return err + return true, err } c.Key, err = crypt.New(key, []byte(c.Options.SharedSecret)) if err != nil { - return err + return true, err + } + + // connects to the other ports of the server for transfer + for i := 1; i < len(c.Options.RelayPorts); i++ { + c.conn[i], err = tcp.ConnectToTCPServer( + fmt.Sprintf("%s:%s", c.Options.RelayAddress, c.Options.RelayPorts[i]), + fmt.Sprintf("%s-%d", utils.SHA256(c.Options.SharedSecret)[:7], i), + ) + if err != nil { + return true, err + } + if !c.Options.IsSender { + go c.receiveData(i) + } } c.Step1ChannelSecured = true } @@ -306,7 +333,7 @@ func (c *Client) processMessage(payload []byte) (err error) { // c.spinner.Stop() fmt.Print("\r") err = fmt.Errorf("peer error: %s", m.Message) - return err + return true, err case "fileinfo": var senderInfo SenderInfo err = json.Unmarshal(m.Bytes, &senderInfo) @@ -331,7 +358,7 @@ func (c *Client) processMessage(payload []byte) (err error) { Type: "error", Message: "refusing files", }) - return fmt.Errorf("refused files") + return true, fmt.Errorf("refused files") } } else { fmt.Fprintf(os.Stderr, "\rReceiving %s (%s) from machine '%s'\n", fname, utils.ByteCountDecimal(totalSize), senderInfo.MachineID) @@ -354,7 +381,6 @@ func (c *Client) processMessage(payload []byte) (err error) { log.Debug("sending close-recipient") err = message.Send(c.conn[0], c.Key, message.Message{ Type: "close-recipient", - Num: m.Num, }) case "close-recipient": c.Step4FileTransfer = false @@ -421,6 +447,53 @@ func (c *Client) updateState() (err error) { // start initiating the process to receive a new file log.Debugf("working on file %d", c.FilesToTransferCurrentNum) + // recipient sets the file + pathToFile := path.Join( + c.FilesToTransfer[c.FilesToTransferCurrentNum].FolderRemote, + c.FilesToTransfer[c.FilesToTransferCurrentNum].Name, + ) + folderForFile, _ := filepath.Split(pathToFile) + os.MkdirAll(folderForFile, os.ModePerm) + var errOpen error + c.CurrentFile, errOpen = os.OpenFile( + pathToFile, + os.O_WRONLY, 0666) + truncate := false + if errOpen == nil { + stat, _ := c.CurrentFile.Stat() + truncate = stat.Size() != c.FilesToTransfer[c.FilesToTransferCurrentNum].Size + } else { + c.CurrentFile, errOpen = os.Create(pathToFile) + if errOpen != nil { + errOpen = errors.Wrap(errOpen, "could not create "+pathToFile) + log.Error(errOpen) + return errOpen + } + truncate = true + } + if truncate { + err := c.CurrentFile.Truncate(c.FilesToTransfer[c.FilesToTransferCurrentNum].Size) + if err != nil { + err = errors.Wrap(err, "could not truncate "+pathToFile) + log.Error(err) + return err + } + } + + // setup the progressbar + c.bar = progressbar.NewOptions64( + c.FilesToTransfer[c.FilesToTransferCurrentNum].Size, + progressbar.OptionOnCompletion(func() { + fmt.Println(" ✔️") + }), + progressbar.OptionSetWidth(8), + progressbar.OptionSetDescription(c.FilesToTransfer[c.FilesToTransferCurrentNum].Name), + progressbar.OptionSetRenderBlankState(true), + progressbar.OptionSetBytes64(c.FilesToTransfer[c.FilesToTransferCurrentNum].Size), + progressbar.OptionSetWriter(os.Stderr), + progressbar.OptionThrottle(100*time.Millisecond), + ) + // recipient requests the file and chunks (if empty, then should receive all chunks) bRequest, _ := json.Marshal(RemoteFileRequest{ CurrentFileChunks: c.CurrentFileChunks, @@ -434,35 +507,123 @@ func (c *Client) updateState() (err error) { return } c.Step3RecipientRequestFile = true - // TODO: receive } if c.Options.IsSender && c.Step3RecipientRequestFile && !c.Step4FileTransfer { log.Debug("start sending data!") - // TODO: send c.Step4FileTransfer = true + // setup the progressbar + c.bar = progressbar.NewOptions64( + c.FilesToTransfer[c.FilesToTransferCurrentNum].Size, + progressbar.OptionOnCompletion(func() { + fmt.Println(" ✔️") + }), + progressbar.OptionSetWidth(8), + progressbar.OptionSetDescription(c.FilesToTransfer[c.FilesToTransferCurrentNum].Name), + progressbar.OptionSetRenderBlankState(true), + progressbar.OptionSetBytes64(c.FilesToTransfer[c.FilesToTransferCurrentNum].Size), + progressbar.OptionSetWriter(os.Stderr), + progressbar.OptionThrottle(100*time.Millisecond), + ) + for i := 1; i < len(c.Options.RelayPorts); i++ { + go c.sendData(i) + } } return } -// Encode encodes the input in base64 -// It can optionally zip the input before encoding -func Encode(obj interface{}) string { - b, err := json.Marshal(obj) +func (c *Client) receiveData(i int) { + + for { + data, err := c.conn[i].Receive() + if err != nil { + log.Errorf("%s: %s", i, err.Error()) + } + data, err = c.Key.Decrypt(data) + if err != nil { + panic(err) + } + data = compress.Decompress(data) + + // get position + var position uint64 + rbuf := bytes.NewReader(data[:8]) + err = binary.Read(rbuf, binary.LittleEndian, &position) + if err != nil { + fmt.Println("binary.Read failed:", err) + } + positionInt64 := int64(position) + + c.mutex.Lock() + n, err := c.CurrentFile.WriteAt(data[8:], positionInt64) + c.mutex.Unlock() + if err != nil { + panic(err) + } + c.bar.Add(n) + if c.bar.State().CurrentBytes == float64(c.FilesToTransfer[c.FilesToTransferCurrentNum].Size) { + log.Debug("finished receiving!") + c.CurrentFile.Close() + log.Debug("sending close-sender") + err = message.Send(c.conn[0], c.Key, message.Message{ + Type: "close-sender", + }) + if err != nil { + panic(err) + } + } + } + + return +} + +func (c *Client) sendData(i int) { + pathToFile := path.Join( + c.FilesToTransfer[c.FilesToTransferCurrentNum].FolderSource, + c.FilesToTransfer[c.FilesToTransferCurrentNum].Name, + ) + log.Debugf("opening %s to read", pathToFile) + f, err := os.Open(pathToFile) if err != nil { panic(err) } + defer f.Close() - return base64.StdEncoding.EncodeToString(b) -} + pos := uint64(0) + curi := float64(0) + for { + // Read file + data := make([]byte, 1000) + n, err := f.Read(data) + if err != nil { + if err == io.EOF { + return + } + panic(err) + } -// Decode decodes the input from base64 -// It can optionally unzip the input after decoding -func Decode(in string, obj interface{}) (err error) { - b, err := base64.StdEncoding.DecodeString(in) - if err != nil { - return + if math.Mod(curi, float64(len(c.Options.RelayPorts)-1))+1 == float64(i) { + posByte := make([]byte, 8) + binary.LittleEndian.PutUint64(posByte, pos) + + dataToSend, err := c.Key.Encrypt( + compress.Compress( + append(posByte, data[:n]...), + ), + ) + if err != nil { + panic(err) + } + + err = c.conn[i].Send(dataToSend) + if err != nil { + panic(err) + } + c.bar.Add(n) + } + + curi++ + pos += uint64(n) } - - err = json.Unmarshal(b, obj) return + }