mirror of https://github.com/schollz/croc.git
add basic ui
This commit is contained in:
parent
d95c90de44
commit
aa0c5acc60
13
main.go
13
main.go
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
113
src/client.go
113
src/client.go
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue