1
1
Fork 0
mirror of https://github.com/schollz/croc.git synced 2025-10-11 13:21:00 +02:00
This commit is contained in:
Zack Scholl 2019-04-12 20:57:10 -07:00
parent 724de7e3c2
commit ba07215226
5 changed files with 130 additions and 173 deletions

1
go.mod
View file

@ -16,6 +16,7 @@ require (
github.com/schollz/spinner v0.0.0-20180925172146-6bbc5f7804f9 github.com/schollz/spinner v0.0.0-20180925172146-6bbc5f7804f9
github.com/sirupsen/logrus v1.4.1 github.com/sirupsen/logrus v1.4.1
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.3.0
github.com/urfave/cli v1.20.0
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5 golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5
golang.org/x/net v0.0.0-20181220203305-927f97764cc3 // indirect golang.org/x/net v0.0.0-20181220203305-927f97764cc3 // indirect
gopkg.in/urfave/cli.v1 v1.20.0 gopkg.in/urfave/cli.v1 v1.20.0

3
go.sum
View file

@ -102,6 +102,7 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/schollz/croc v3.0.6+incompatible h1:rCfc8MGgcGjNW2/qSoulPh8CRGH+Ej4i3RWYOwhX9pE=
github.com/schollz/mnemonicode v1.0.1 h1:LiH5hwADZwjwnfXsaD4xgnMyTAtaKHN+e5AyjRU6WSU= github.com/schollz/mnemonicode v1.0.1 h1:LiH5hwADZwjwnfXsaD4xgnMyTAtaKHN+e5AyjRU6WSU=
github.com/schollz/mnemonicode v1.0.1/go.mod h1:cl4UAOhUV0mkdjMj/QYaUZbZZdF8BnOqoz8rHMzwboY= github.com/schollz/mnemonicode v1.0.1/go.mod h1:cl4UAOhUV0mkdjMj/QYaUZbZZdF8BnOqoz8rHMzwboY=
github.com/schollz/pake v1.1.0 h1:+tYqsPVkuirFpmeRePjYTUhIHHKLufdmd7QfuspaXCk= github.com/schollz/pake v1.1.0 h1:+tYqsPVkuirFpmeRePjYTUhIHHKLufdmd7QfuspaXCk=
@ -121,6 +122,8 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/tscholl2/siec v0.0.0-20180721101609-21667da05937 h1:lhssCpSe3TjKcbvUoPzFMuv9oUyZDgI3Cmgolfw2C90= github.com/tscholl2/siec v0.0.0-20180721101609-21667da05937 h1:lhssCpSe3TjKcbvUoPzFMuv9oUyZDgI3Cmgolfw2C90=
github.com/tscholl2/siec v0.0.0-20180721101609-21667da05937/go.mod h1:KL9+ubr1JZdaKjgAaHr+tCytEncXBa1pR6FjbTsOJnw= 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/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

46
main.go
View file

@ -1,10 +1,9 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"github.com/schollz/croc/v5/src/croc" "github.com/schollz/croc/v5/src/cli"
) )
func main() { func main() {
@ -24,26 +23,29 @@ func main() {
// } // }
// log.Debugln(bytes.Equal(buffer[:bytesread], emptyBuffer[:bytesread])) // log.Debugln(bytes.Equal(buffer[:bytesread], emptyBuffer[:bytesread]))
// } // }
var sender bool // var sender bool
flag.BoolVar(&sender, "sender", false, "sender") // flag.BoolVar(&sender, "sender", false, "sender")
flag.Parse() // flag.Parse()
c, err := croc.New(sender, "foo") // c, err := croc.New(sender, "foo")
if err != nil { // if err != nil {
panic(err) // panic(err)
} // }
if sender { // if sender {
err = c.Send(croc.TransferOptions{ // err = c.Send(croc.TransferOptions{
// PathToFile: "../wskeystore/README.md", // // PathToFile: "../wskeystore/README.md",
// PathToFile: "./src/croc/croc.go", // // PathToFile: "./src/croc/croc.go",
// PathToFiles: []string{"C:\\Users\\zacks\\go\\src\\github.com\\schollz\\croc\\src\\croc\\croc.go", "croc.exe"}, // // PathToFiles: []string{"C:\\Users\\zacks\\go\\src\\github.com\\schollz\\croc\\src\\croc\\croc.go", "croc.exe"},
PathToFiles: []string{"croc2.exe", "croc3.exe"}, //,"croc2.exe", "croc3.exe"}, // PathToFiles: []string{"croc2.exe", "croc3.exe"}, //,"croc2.exe", "croc3.exe"},
//PathToFiles: []string{"README.md"}, //,"croc2.exe", "croc3.exe"}, // //PathToFiles: []string{"README.md"}, //,"croc2.exe", "croc3.exe"},
KeepPathInRemote: false, // KeepPathInRemote: false,
}) // })
} else { // } else {
err = c.Receive() // err = c.Receive()
} // }
if err != nil { // if err != nil {
// fmt.Println(err)
// }
if err := cli.Run(); err != nil {
fmt.Println(err) fmt.Println(err)
} }
} }

View file

@ -1,6 +1,7 @@
package cli package cli
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -11,16 +12,16 @@ import (
"strings" "strings"
"time" "time"
humanize "github.com/dustin/go-humanize" "github.com/schollz/croc/v5/src/croc"
"github.com/pkg/errors"
"github.com/schollz/croc/v5/src/utils" "github.com/schollz/croc/v5/src/utils"
"github.com/skratchdot/open-golang/open"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
var Version string var Version string
var cr *croc.Client
func Run() (err error) {
func Run() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
app := cli.NewApp() app := cli.NewApp()
app.Name = "croc" app.Name = "croc"
@ -40,8 +41,6 @@ func Run() {
Description: "send a file over the relay", Description: "send a file over the relay",
ArgsUsage: "[filename]", ArgsUsage: "[filename]",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{Name: "no-compress, o", Usage: "disable compression"},
cli.BoolFlag{Name: "no-encrypt, e", Usage: "disable encryption"},
cli.StringFlag{Name: "code, c", Usage: "codephrase used to connect to relay"}, cli.StringFlag{Name: "code, c", Usage: "codephrase used to connect to relay"},
}, },
HelpName: "croc send", HelpName: "croc send",
@ -49,32 +48,12 @@ func Run() {
return send(c) return send(c)
}, },
}, },
{
Name: "relay",
Usage: "start a croc relay",
Description: "the croc relay will handle websocket and TCP connections",
Flags: []cli.Flag{},
HelpName: "croc relay",
Action: func(c *cli.Context) error {
return relay(c)
},
},
{
Name: "config",
Usage: "generates a config file",
Description: "the croc config can be used to set static parameters",
Flags: []cli.Flag{},
HelpName: "croc config",
Action: func(c *cli.Context) error {
return saveDefaultConfig(c)
},
},
} }
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
cli.BoolFlag{Name: "debug", Usage: "increase verbosity (a lot)"}, cli.BoolFlag{Name: "debug", Usage: "increase verbosity (a lot)"},
cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"}, cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"},
cli.BoolFlag{Name: "stdout", Usage: "redirect file to stdout"}, cli.BoolFlag{Name: "stdout", Usage: "redirect file to stdout"},
cli.StringFlag{Name: "port", Value: "8153", Usage: "port that the websocket listens on"}, cli.StringFlag{Name: "relay", Value: "198.199.67.130:6372", Usage: "address of the relay"},
cli.StringFlag{Name: "out", Value: ".", Usage: "specify an output folder to receive the file"}, cli.StringFlag{Name: "out", Value: ".", Usage: "specify an output folder to receive the file"},
} }
app.EnableBashCompletion = true app.EnableBashCompletion = true
@ -95,43 +74,26 @@ func Run() {
return receive(c) return receive(c)
} }
app.Before = func(c *cli.Context) error { app.Before = func(c *cli.Context) error {
cr = croc.Init(c.GlobalBool("debug")) var err error
cr.Version = Version cr, err = croc.New(croc.Options{
cr.AllowLocalDiscovery = true Debug: c.GlobalBool("debug"),
cr.Address = c.GlobalString("addr") NoPrompt: c.GlobalBool("yes"),
cr.AddressTCPPorts = strings.Split(c.GlobalString("addr-tcp"), ",") AddressRelay: c.GlobalString("relay"),
cr.AddressWebsocketPort = c.GlobalString("addr-ws") Stdout: c.GlobalBool("stdout"),
cr.NoRecipientPrompt = c.GlobalBool("yes") })
cr.Stdout = c.GlobalBool("stdout") return err
cr.LocalOnly = c.GlobalBool("local")
cr.NoLocal = c.GlobalBool("no-local")
cr.ShowText = true
cr.RelayWebsocketPort = c.String("port")
cr.RelayTCPPorts = strings.Split(c.String("tcp-port"), ",")
cr.CurveType = c.String("curve")
if c.GlobalBool("force-tcp") {
cr.ForceSend = 2
}
if c.GlobalBool("force-web") {
cr.ForceSend = 1
}
return nil
} }
err := app.Run(os.Args) return app.Run(os.Args)
if err != nil {
fmt.Fprintf(os.Stderr, "\r\n%s", err.Error())
}
fmt.Fprintf(os.Stderr, "\r\n")
} }
func saveDefaultConfig(c *cli.Context) error { // func saveDefaultConfig(c *cli.Context) error {
return croc.SaveDefaultConfig() // return croc.SaveDefaultConfig()
} // }
func send(c *cli.Context) error { func send(c *cli.Context) (err error) {
var fnames []string
stat, _ := os.Stdin.Stat() stat, _ := os.Stdin.Stat()
var fname string
if (stat.Mode() & os.ModeCharDevice) == 0 { if (stat.Mode() & os.ModeCharDevice) == 0 {
f, err := ioutil.TempFile(".", "croc-stdin-") f, err := ioutil.TempFile(".", "croc-stdin-")
if err != nil { if err != nil {
@ -145,102 +107,91 @@ func send(c *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
fname = f.Name() fnames = []string{f.Name()}
defer func() { defer func() {
err = os.Remove(fname) err = os.Remove(fnames[0])
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
}() }()
} else { } else {
fname = c.Args().First() fnames = append([]string{c.Args().First()}, c.Args().Tail()...)
} }
if fname == "" { if len(fnames) == 0 {
return errors.New("must specify file: croc send [filename]") return errors.New("must specify file: croc send [filename]")
} }
cr.UseCompression = !c.Bool("no-compress")
cr.UseEncryption = !c.Bool("no-encrypt")
if c.String("code") != "" { if c.String("code") != "" {
cr.Codephrase = c.String("code") cr.Options.SharedSecret = c.String("code")
} }
cr.LoadConfig() // cr.LoadConfig()
if len(cr.Codephrase) == 0 { if len(cr.Options.SharedSecret) == 0 {
// generate code phrase // generate code phrase
cr.Codephrase = utils.GetRandomName() cr.Options.SharedSecret = utils.GetRandomName()
} }
// print the text paths := []string{}
finfo, err := os.Stat(fname) for _, fname := range fnames {
if err != nil { stat, err := os.Stat(fname)
return err
}
fname, _ = filepath.Abs(fname)
fname = filepath.Clean(fname)
_, filename := filepath.Split(fname)
fileOrFolder := "file"
fsize := finfo.Size()
if finfo.IsDir() {
fileOrFolder = "folder"
fsize, err = dirSize(fname)
if err != nil { if err != nil {
return err return err
} }
if stat.IsDir() {
err = filepath.Walk(fname,
func(pathName string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
paths = append(paths, filepath.ToSlash(pathName))
}
return nil
})
if err != nil {
return err
}
} else {
paths = append(paths, filepath.ToSlash(fname))
}
} }
fmt.Fprintf(os.Stderr,
"Sending %s %s named '%s'\nCode is: %s\nOn the other computer, please run:\n\ncroc %s\n\n", err = cr.Send(croc.TransferOptions{
humanize.Bytes(uint64(fsize)), PathToFiles: paths,
fileOrFolder, KeepPathInRemote: false,
filename, })
cr.Codephrase,
cr.Codephrase, return
)
if cr.Debug {
croc.SetDebugLevel("debug")
}
return cr.Send(fname, cr.Codephrase)
} }
func receive(c *cli.Context) error { func receive(c *cli.Context) (err error) {
if c.GlobalString("code") != "" { if c.GlobalString("code") != "" {
cr.Codephrase = c.GlobalString("code") cr.Options.SharedSecret = c.GlobalString("code")
} }
if c.Args().First() != "" { if c.Args().First() != "" {
cr.Codephrase = c.Args().First() cr.Options.SharedSecret = c.Args().First()
}
if cr.Options.SharedSecret == "" {
cr.Options.SharedSecret = utils.GetInput("Enter receive code: ")
} }
if c.GlobalString("out") != "" { if c.GlobalString("out") != "" {
os.Chdir(c.GlobalString("out")) os.Chdir(c.GlobalString("out"))
} }
cr.LoadConfig()
openFolder := false err = cr.Receive()
if len(os.Args) == 1 { return
// open folder since they didn't give any arguments
openFolder = true
}
if cr.Codephrase == "" {
cr.Codephrase = utils.GetInput("Enter receive code: ")
}
if cr.Debug {
croc.SetDebugLevel("debug")
}
err := cr.Receive(cr.Codephrase)
if err == nil && openFolder {
cwd, _ := os.Getwd()
open.Run(cwd)
}
return err
} }
func relay(c *cli.Context) error { // func relay(c *cli.Context) error {
return cr.Relay() // return cr.Relay()
} // }
func dirSize(path string) (int64, error) { // func dirSize(path string) (int64, error) {
var size int64 // var size int64
err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error { // err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
if !info.IsDir() { // if !info.IsDir() {
size += info.Size() // size += info.Size()
} // }
return err // return err
}) // })
return size, err // return size, err
} // }

View file

@ -54,11 +54,9 @@ func Debug(debug bool) {
type Client struct { type Client struct {
Options Options Options Options
// basic setup // basic setup
redisdb *redis.Client redisdb *redis.Client
log *logrus.Entry log *logrus.Entry
IsSender bool Pake *pake.Pake
SharedSecret string
Pake *pake.Pake
// steps involved in forming relationship // steps involved in forming relationship
Step1ChannelSecured bool Step1ChannelSecured bool
@ -147,20 +145,22 @@ func New(ops Options) (c *Client, err error) {
c = new(Client) c = new(Client)
// setup basic info // setup basic info
c.IsSender = ops.Sender c.Options = ops
c.SharedSecret = ops.SharedSecret
c.SharedSecret = ops.SharedSecret // set channels
if sender { if c.Options.IsSender {
c.nameOutChannel = c.SharedSecret + "2" c.nameOutChannel = c.Options.SharedSecret + "2"
c.nameInChannel = c.SharedSecret + "1" c.nameInChannel = c.Options.SharedSecret + "1"
} else { } else {
c.nameOutChannel = c.SharedSecret + "1" c.nameOutChannel = c.Options.SharedSecret + "1"
c.nameInChannel = c.SharedSecret + "2" c.nameInChannel = c.Options.SharedSecret + "2"
} }
Debug(c.Options.Debug)
// initialize redis for communication in establishing channel // initialize redis for communication in establishing channel
c.redisdb = redis.NewClient(&redis.Options{ c.redisdb = redis.NewClient(&redis.Options{
Addr: "198.199.67.130:6372", Addr: c.Options.AddressRelay,
Password: "", Password: "",
DB: 4, DB: 4,
WriteTimeout: 1 * time.Hour, WriteTimeout: 1 * time.Hour,
@ -180,10 +180,10 @@ func New(ops Options) (c *Client, err error) {
c.incomingMessageChannel = pubsub.Channel() c.incomingMessageChannel = pubsub.Channel()
// initialize pake // initialize pake
if c.IsSender { if c.Options.IsSender {
c.Pake, err = pake.Init([]byte{1, 2, 3}, 1, elliptic.P521(), 1*time.Microsecond) c.Pake, err = pake.Init([]byte(c.Options.SharedSecret), 1, elliptic.P521(), 1*time.Microsecond)
} else { } else {
c.Pake, err = pake.Init([]byte{1, 2, 3}, 0, elliptic.P521(), 1*time.Microsecond) c.Pake, err = pake.Init([]byte(c.Options.SharedSecret), 0, elliptic.P521(), 1*time.Microsecond)
} }
if err != nil { if err != nil {
return return
@ -193,7 +193,7 @@ func New(ops Options) (c *Client, err error) {
c.log = log.WithFields(logrus.Fields{ c.log = log.WithFields(logrus.Fields{
"is": "sender", "is": "sender",
}) })
if !c.IsSender { if !c.Options.IsSender {
c.log = log.WithFields(logrus.Fields{ c.log = log.WithFields(logrus.Fields{
"is": "recipient", "is": "recipient",
}) })
@ -223,7 +223,7 @@ func (c *Client) Receive() (err error) {
} }
func (c *Client) transfer(options TransferOptions) (err error) { func (c *Client) transfer(options TransferOptions) (err error) {
if c.IsSender { if c.Options.IsSender {
c.FilesToTransfer = make([]FileInfo, len(options.PathToFiles)) c.FilesToTransfer = make([]FileInfo, len(options.PathToFiles))
totalFilesSize := int64(0) totalFilesSize := int64(0)
for i, pathToFile := range options.PathToFiles { for i, pathToFile := range options.PathToFiles {
@ -299,7 +299,7 @@ func (c *Client) transfer(options TransferOptions) (err error) {
// if recipient, initialize with sending pake information // if recipient, initialize with sending pake information
c.log.Debug("ready") c.log.Debug("ready")
if !c.IsSender && !c.Step1ChannelSecured { if !c.Options.IsSender && !c.Step1ChannelSecured {
err = c.redisdb.Publish(c.nameOutChannel, Message{ err = c.redisdb.Publish(c.nameOutChannel, Message{
Type: "pake", Type: "pake",
Bytes: c.Pake.Bytes(), Bytes: c.Pake.Bytes(),
@ -392,7 +392,7 @@ func (c *Client) processMessage(m Message) (err error) {
if err != nil { if err != nil {
return return
} }
if (notVerified && c.Pake.IsVerified() && !c.IsSender) || !c.Pake.IsVerified() { if (notVerified && c.Pake.IsVerified() && !c.Options.IsSender) || !c.Pake.IsVerified() {
err = c.redisdb.Publish(c.nameOutChannel, Message{ err = c.redisdb.Publish(c.nameOutChannel, Message{
Type: "pake", Type: "pake",
Bytes: c.Pake.Bytes(), Bytes: c.Pake.Bytes(),
@ -516,7 +516,7 @@ func (c *Client) processMessage(m Message) (err error) {
} }
func (c *Client) updateState() (err error) { func (c *Client) updateState() (err error) {
if c.IsSender && c.Step1ChannelSecured && !c.Step2FileInfoTransfered { if c.Options.IsSender && c.Step1ChannelSecured && !c.Step2FileInfoTransfered {
var b []byte var b []byte
b, err = json.Marshal(SenderInfo{ b, err = json.Marshal(SenderInfo{
MachineID: c.machineID, MachineID: c.machineID,
@ -536,7 +536,7 @@ func (c *Client) updateState() (err error) {
} }
c.Step2FileInfoTransfered = true c.Step2FileInfoTransfered = true
} }
if !c.IsSender && c.Step2FileInfoTransfered && !c.Step3RecipientRequestFile { if !c.Options.IsSender && c.Step2FileInfoTransfered && !c.Step3RecipientRequestFile {
// find the next file to transfer and send that number // find the next file to transfer and send that number
// if the files are the same size, then look for missing chunks // if the files are the same size, then look for missing chunks
finished := true finished := true
@ -585,7 +585,7 @@ func (c *Client) updateState() (err error) {
c.Step3RecipientRequestFile = true c.Step3RecipientRequestFile = true
err = c.dataChannelReceive() err = c.dataChannelReceive()
} }
if c.IsSender && c.Step3RecipientRequestFile && !c.Step4FileTransfer { if c.Options.IsSender && c.Step3RecipientRequestFile && !c.Step4FileTransfer {
c.log.Debug("start sending data!") c.log.Debug("start sending data!")
err = c.dataChannelSend() err = c.dataChannelSend()
c.Step4FileTransfer = true c.Step4FileTransfer = true