add basic ui

This commit is contained in:
Zack Scholl 2018-06-30 10:45:23 -07:00
parent d95c90de44
commit aa0c5acc60
7 changed files with 170 additions and 45 deletions

13
main.go
View File

@ -79,18 +79,16 @@ func main() {
fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n")
}
app.Action = func(c *cli.Context) error {
fmt.Printf("made it!\n")
return nil
return cr.Receive(c.Args().First())
}
app.Before = func(c *cli.Context) error {
cr = croc.Init()
cr.AllowLocalDiscovery = true
cr.WebsocketAddress = c.GlobalString("relay")
cr.Debug = c.GlobalBool("debug")
cr.SetDebug(c.GlobalBool("debug"))
cr.Yes = c.GlobalBool("yes")
cr.Stdout = c.GlobalBool("stdout")
cr.LocalOnly = c.GlobalBool("local")
cr.CodePhrase = c.GlobalString("code")
return nil
}
@ -106,14 +104,11 @@ func send(c *cli.Context) error {
}
cr.UseCompression = c.GlobalBoolT("compress")
cr.UseEncryption = c.GlobalBoolT("encrypt")
fmt.Println("sending")
return nil
return cr.Send(c.Args().First(), c.GlobalString("code"))
}
func receive(c *cli.Context) error {
fmt.Println("receive")
return nil
return cr.Receive(c.GlobalString("code"))
}
func relay(c *cli.Context) error {

View File

@ -15,12 +15,10 @@ func (c *Croc) Relay() error {
// Send will take an existing file or folder and send it through the croc relay
func (c *Croc) Send(fname string, codephrase string) (err error) {
err = c.client(0, codephrase, fname)
return
return c.client(0, codephrase, fname)
}
// Receive will receive something through the croc relay
func (c *Croc) Receive(codephrase string) (err error) {
err = c.client(1, codephrase)
return
return c.client(1, codephrase)
}

View File

@ -1,6 +1,26 @@
package croc
import (
"os"
"strconv"
)
func (c *Croc) cleanup() {
// TODO
// erase all the croc files and their possible numbers
for i := 0; i < 100; i++ {
fname := c.crocFile + "." + strconv.Itoa(i)
if !exists(fname) {
break
}
os.Remove(fname)
}
for i := 0; i < 100; i++ {
fname := c.crocFileEncrypted + "." + strconv.Itoa(i)
if !exists(fname) {
break
}
os.Remove(fname)
}
os.Remove(c.crocFile)
os.Remove(c.crocFileEncrypted)
}

View File

@ -2,6 +2,7 @@ package croc
import (
"encoding/json"
"fmt"
"io"
"net"
"net/url"
@ -16,10 +17,48 @@ import (
"github.com/gorilla/websocket"
"github.com/pkg/errors"
"github.com/schollz/croc/src/pake"
"github.com/schollz/progressbar"
)
func (c *Croc) client(role int, codePhrase string, fname ...string) (err error) {
defer log.Flush()
defer c.cleanup()
// initialize the channel data for this client
c.cs.Lock()
c.cs.channel.codePhrase = codePhrase
if len(codePhrase) > 0 {
if len(codePhrase) < 4 {
err = errors.New("code phrase must be more than 4 characters")
c.cs.Unlock()
return
}
c.cs.channel.Channel = codePhrase[:3]
c.cs.channel.passPhrase = codePhrase[3:]
} else {
// TODO
if role == 0 {
// generate code phrase
codePhrase = getRandomName()
dash := strings.Index(codePhrase, "-")
c.cs.channel.Channel = codePhrase[:dash]
c.cs.channel.passPhrase = codePhrase[dash:]
} else {
codePhrase = promptCodePhrase()
if len(codePhrase) < 4 {
err = errors.New("code phrase must be more than 4 characters")
c.cs.Unlock()
return
}
c.cs.channel.Channel = codePhrase[:3]
c.cs.channel.passPhrase = codePhrase[3:]
}
c.cs.channel.codePhrase = codePhrase
}
log.Debugf("codephrase: '%s'", codePhrase)
log.Debugf("channel: '%s'", c.cs.channel.Channel)
log.Debugf("passPhrase: '%s'", c.cs.channel.passPhrase)
channel := c.cs.channel.Channel
c.cs.Unlock()
if role == 0 {
if len(fname) == 0 {
@ -32,26 +71,6 @@ func (c *Croc) client(role int, codePhrase string, fname ...string) (err error)
}
}
// initialize the channel data for this client
c.cs.Lock()
c.cs.channel.codePhrase = codePhrase
if len(codePhrase) > 0 {
if len(codePhrase) < 4 {
err = errors.New("code phrase must be more than 4 characters")
return
}
c.cs.channel.Channel = codePhrase[:3]
c.cs.channel.passPhrase = codePhrase[3:]
} else {
// TODO
// generate code phrase
c.cs.channel.Channel = "chou"
c.cs.channel.passPhrase = codePhrase[3:]
}
channel := c.cs.channel.Channel
c.cs.Unlock()
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
@ -83,7 +102,7 @@ func (c *Croc) client(role int, codePhrase string, fname ...string) (err error)
log.Debugf("sender read error:", err)
return
}
//log.Debugf("recv: %s", cd.String2())
log.Debugf("recv: %s", cd.String2())
err = c.processState(cd)
if err != nil {
log.Warn(err)
@ -150,6 +169,17 @@ func (c *Croc) client(role int, codePhrase string, fname ...string) (err error)
c.cs.Lock()
if c.cs.channel.finishedHappy {
log.Info("file recieved!")
if c.cs.channel.Role == 0 {
fmt.Fprintf(os.Stderr, "\nTransfer complete.\n")
} else {
fmt.Fprintf(os.Stderr, "\nReceived file written to %s", c.cs.channel.fileMetaData.Name)
}
} else {
if c.cs.channel.Error != "" {
err = errors.New(c.cs.channel.Error)
} else {
err = errors.New("one party canceled, file not transfered")
}
}
c.cs.Unlock()
return
@ -242,8 +272,6 @@ func (c *Croc) processState(cd channelData) (err error) {
// process the client state
if c.cs.channel.Pake.IsVerified() && !c.cs.channel.isReady && c.cs.channel.EncryptedFileMetaData.Encrypted != nil {
// TODO:
// check if the user still wants to recieve file
// decrypt the meta data
log.Debugf("encrypted meta data: %+v", c.cs.channel.EncryptedFileMetaData)
@ -265,6 +293,18 @@ func (c *Croc) processState(cd channelData) (err error) {
}
log.Debugf("meta data: %+v", c.cs.channel.fileMetaData)
// check if the user still wants to receive the file
if c.cs.channel.Role == 1 {
if !c.Yes {
if !promptOkayToRecieve(c.cs.channel.fileMetaData) {
log.Debug("sending close signal")
c.cs.channel.Close = true
c.cs.channel.Error = "refusing file"
c.cs.channel.ws.WriteJSON(c.cs.channel)
}
}
}
// spawn TCP connections
c.cs.channel.isReady = true
go c.spawnConnections(c.cs.channel.Role)
@ -344,9 +384,17 @@ func (c *Croc) dialUp() (err error) {
}
time.Sleep(10 * time.Millisecond)
}
c.cs.RLock()
if i == 0 {
c.cs.Lock()
c.bar = progressbar.NewOptions(c.cs.channel.fileMetaData.Size, progressbar.OptionSetWriter(os.Stderr))
c.cs.Unlock()
if role == 0 {
fmt.Fprintf(os.Stderr, "\nSending...\n")
} else {
fmt.Fprintf(os.Stderr, "\nReceiving...\n")
}
}
c.cs.RUnlock()
if role == 0 {
log.Debug("send file")
for {
@ -360,7 +408,7 @@ func (c *Croc) dialUp() (err error) {
}
log.Debug("sending file")
filename := c.crocFileEncrypted + "." + strconv.Itoa(i)
err = sendFile(filename, i, connection)
err = c.sendFile(filename, i, connection)
} else {
go func() {
time.Sleep(10 * time.Millisecond)
@ -378,8 +426,9 @@ func (c *Croc) dialUp() (err error) {
}()
receiveFileName := c.crocFileEncrypted + "." + strconv.Itoa(i)
log.Debugf("receiving file into %s", receiveFileName)
err = receiveFile(receiveFileName, i, connection)
err = c.receiveFile(receiveFileName, i, connection)
}
c.bar.Finish()
errorChan <- err
}(channel, uuid, port, i, errorChan)
}
@ -398,7 +447,7 @@ func (c *Croc) dialUp() (err error) {
return
}
func receiveFile(filename string, id int, connection net.Conn) error {
func (c *Croc) receiveFile(filename string, id int, connection net.Conn) error {
log.Debug("waiting for chunk size from sender")
fileSizeBuffer := make([]byte, 10)
connection.Read(fileSizeBuffer)
@ -435,16 +484,19 @@ func receiveFile(filename string, id int, connection net.Conn) error {
}
written, _ := io.CopyN(newFile, connection, bufferSize)
receivedBytes += written
c.bar.Add(int(written))
if !receivedFirstBytes {
receivedFirstBytes = true
log.Debug(id, "Receieved first bytes!")
log.Debug(id, "Received first bytes!")
}
}
log.Debug(id, "received file")
return nil
}
func sendFile(filename string, id int, connection net.Conn) error {
func (c *Croc) sendFile(filename string, id int, connection net.Conn) error {
// open encrypted file chunk, if it exists
log.Debug("opening encrypted file chunk: " + filename)
file, err := os.Open(filename)
@ -481,6 +533,7 @@ func sendFile(filename string, id int, connection net.Conn) error {
_, err := file.Read(sendBuffer)
written, _ := connection.Write(sendBuffer)
totalBytesSent += written
c.bar.Add(written)
// if errWrite != nil {
// errWrite = errors.Wrap(errWrite, "problem writing to connection")
// return errWrite

View File

@ -79,6 +79,7 @@ func (c *Croc) processFile(src string) (err error) {
c.cs.Lock()
defer c.cs.Unlock()
c.cs.channel.fileMetaData = fd
go showIntro(c.cs.channel.codePhrase, fd)
return
}

View File

@ -8,6 +8,7 @@ import (
"github.com/gorilla/websocket"
"github.com/schollz/croc/src/pake"
"github.com/schollz/progressbar"
)
const (
@ -41,7 +42,8 @@ type Croc struct {
rs relayState
// cs keeps the client state
cs clientState
cs clientState
bar *progressbar.ProgressBar
// crocFile is the name of the file that is prepared to sent
crocFile string
@ -64,6 +66,7 @@ func Init() (c *Croc) {
c.rs.channel = make(map[string]*channelData)
c.cs.channel = new(channelData)
c.rs.Unlock()
return
}

55
src/prompts.go Normal file
View File

@ -0,0 +1,55 @@
package croc
import (
"bufio"
"fmt"
"os"
"strings"
humanize "github.com/dustin/go-humanize"
)
func promptCodePhrase() string {
return getInput("Enter receive code: ")
}
func promptOkayToRecieve(f FileMetaData) (ok bool) {
fileOrFolder := "file"
if f.IsDir {
fileOrFolder = "folder"
}
return "y" == getInput(fmt.Sprintf(
`Receiving %s (%s) into: %s
ok? (y/N): `,
fileOrFolder,
humanize.Bytes(uint64(f.Size)),
f.Name,
))
}
func showIntro(code string, f FileMetaData) {
fileOrFolder := "file"
if f.IsDir {
fileOrFolder = "folder"
}
fmt.Fprintf(os.Stderr,
`Sending %s %s named '%s'
Code is: %s
On the other computer, please run:
croc %s
`,
humanize.Bytes(uint64(f.Size)),
fileOrFolder,
f.Name,
code,
code,
)
}
func getInput(prompt string) string {
reader := bufio.NewReader(os.Stdin)
fmt.Fprintf(os.Stderr, "%s", prompt)
text, _ := reader.ReadString('\n')
return strings.TrimSpace(text)
}