croc/src/cli/cli.go

328 lines
7.8 KiB
Go
Raw Normal View History

2018-10-16 21:23:01 +02:00
package cli
import (
2019-07-18 00:19:32 +02:00
"encoding/json"
2019-04-30 01:09:37 +02:00
"errors"
2018-10-16 21:23:01 +02:00
"fmt"
"io"
"io/ioutil"
"os"
2019-07-17 23:55:43 +02:00
"path"
2018-10-16 21:23:01 +02:00
"path/filepath"
2018-10-23 05:34:04 +02:00
"runtime"
2018-10-16 21:23:01 +02:00
"strings"
"time"
2019-04-30 01:09:37 +02:00
"github.com/schollz/croc/v6/src/croc"
"github.com/schollz/croc/v6/src/models"
2019-04-30 06:25:30 +02:00
"github.com/schollz/croc/v6/src/tcp"
2019-04-30 01:09:37 +02:00
"github.com/schollz/croc/v6/src/utils"
2019-07-17 22:33:02 +02:00
log "github.com/schollz/logger"
2018-10-16 21:23:01 +02:00
"github.com/urfave/cli"
)
var Version string
2019-04-30 01:09:37 +02:00
func Run() (err error) {
// use all of the processors
2018-10-23 05:34:04 +02:00
runtime.GOMAXPROCS(runtime.NumCPU())
2018-10-16 21:23:01 +02:00
app := cli.NewApp()
app.Name = "croc"
if Version == "" {
2019-07-15 04:33:47 +02:00
Version = "v6.0.12-fbbdd1b"
2018-10-16 21:23:01 +02:00
}
app.Version = Version
app.Compiled = time.Now()
app.Usage = "easily and securely transfer stuff from one computer to another"
app.UsageText = "croc allows any two computers to directly and securely transfer files"
// app.ArgsUsage = "[args and such]"
app.Commands = []cli.Command{
{
Name: "send",
Usage: "send a file",
Description: "send a file over the relay",
ArgsUsage: "[filename]",
Flags: []cli.Flag{
cli.StringFlag{Name: "code, c", Usage: "codephrase used to connect to relay"},
cli.BoolFlag{Name: "no-local", Usage: "disable local relay when sending"},
2019-05-01 21:48:09 +02:00
cli.StringFlag{Name: "ports", Value: "9009,9010,9011,9012,9013", Usage: "ports of the local relay (optional)"},
2018-10-16 21:23:01 +02:00
},
HelpName: "croc send",
Action: func(c *cli.Context) error {
return send(c)
},
},
2019-04-30 06:25:30 +02:00
{
Name: "relay",
Description: "start relay",
HelpName: "croc relay",
Action: func(c *cli.Context) error {
return relay(c)
},
2019-05-01 21:48:09 +02:00
Flags: []cli.Flag{
cli.StringFlag{Name: "ports", Value: "9009,9010,9011,9012,9013", Usage: "ports of the relay"},
},
2019-04-30 06:25:30 +02:00
},
2018-10-16 21:23:01 +02:00
}
app.Flags = []cli.Flag{
2019-07-18 00:19:32 +02:00
cli.BoolFlag{Name: "remember", Usage: "save these settings to reuse next time"},
2018-10-16 21:23:01 +02:00
cli.BoolFlag{Name: "debug", Usage: "increase verbosity (a lot)"},
cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"},
cli.BoolFlag{Name: "stdout", Usage: "redirect file to stdout"},
cli.StringFlag{Name: "relay", Value: models.DEFAULT_RELAY, Usage: "address of the relay"},
2018-10-22 15:36:36 +02:00
cli.StringFlag{Name: "out", Value: ".", Usage: "specify an output folder to receive the file"},
2018-10-16 21:23:01 +02:00
}
app.EnableBashCompletion = true
app.HideHelp = false
app.HideVersion = false
app.BashComplete = func(c *cli.Context) {
fmt.Fprintf(c.App.Writer, "send\nreceive\relay")
}
app.Action = func(c *cli.Context) error {
2018-11-01 15:08:57 +01:00
// if trying to send but forgot send, let the user know
if c.Args().First() != "" && utils.Exists(c.Args().First()) {
_, fname := filepath.Split(c.Args().First())
yn := utils.GetInput(fmt.Sprintf("Did you mean to send '%s'? (y/n) ", fname))
2018-11-01 15:08:57 +01:00
if strings.ToLower(yn) == "y" {
return send(c)
}
}
2018-10-16 21:23:01 +02:00
return receive(c)
}
2019-04-30 01:09:37 +02:00
return app.Run(os.Args)
2018-10-16 21:23:01 +02:00
}
2019-07-17 23:55:43 +02:00
func getConfigDir() (homedir string, err error) {
homedir, err = os.UserHomeDir()
2019-07-17 22:33:02 +02:00
if err != nil {
log.Error(err)
return
}
2019-07-17 23:55:43 +02:00
homedir = path.Join(homedir, ".config", "croc")
if _, err := os.Stat(homedir); os.IsNotExist(err) {
log.Debugf("creating home directory %s", homedir)
err = os.MkdirAll(homedir, 0700)
}
2019-07-17 22:33:02 +02:00
return
}
2019-04-30 01:09:37 +02:00
2019-07-17 22:33:02 +02:00
func send(c *cli.Context) (err error) {
2019-07-18 00:19:32 +02:00
if c.GlobalBool("debug") {
log.SetLevel("debug")
log.Debug("debug mode on")
}
configFile, err := getConfigDir()
if err != nil {
log.Error(err)
return
}
configFile = path.Join(configFile, "send.json")
2019-07-18 02:06:52 +02:00
crocOptions := croc.Options{
SharedSecret: c.String("code"),
IsSender: true,
Debug: c.GlobalBool("debug"),
NoPrompt: c.GlobalBool("yes"),
RelayAddress: c.GlobalString("relay"),
Stdout: c.GlobalBool("stdout"),
DisableLocal: c.Bool("no-local"),
RelayPorts: strings.Split(c.String("ports"), ","),
}
2019-07-18 01:23:50 +02:00
b, errOpen := ioutil.ReadFile(configFile)
2019-07-18 01:26:42 +02:00
if errOpen == nil && !c.GlobalBool("remember") {
2019-07-18 02:06:52 +02:00
var rememberedOptions croc.Options
err = json.Unmarshal(b, &rememberedOptions)
2019-07-18 01:23:50 +02:00
if err != nil {
log.Error(err)
return
}
2019-07-18 02:06:52 +02:00
// update anything that isn't explicitly set
if !c.GlobalIsSet("relay") {
crocOptions.RelayAddress = rememberedOptions.RelayAddress
2019-07-18 01:23:50 +02:00
}
2019-07-18 02:06:52 +02:00
if !c.IsSet("no-local") {
crocOptions.DisableLocal = rememberedOptions.DisableLocal
2019-07-18 01:23:50 +02:00
}
2019-07-18 02:06:52 +02:00
if !c.IsSet("ports") {
crocOptions.RelayPorts = rememberedOptions.RelayPorts
2019-07-18 01:23:50 +02:00
}
2019-07-18 02:06:52 +02:00
if !c.IsSet("code") {
crocOptions.SharedSecret = rememberedOptions.SharedSecret
2019-07-18 01:23:50 +02:00
}
}
2019-04-30 01:09:37 +02:00
var fnames []string
2018-10-16 21:23:01 +02:00
stat, _ := os.Stdin.Stat()
if (stat.Mode() & os.ModeCharDevice) == 0 {
f, err := ioutil.TempFile(".", "croc-stdin-")
if err != nil {
return err
}
_, err = io.Copy(f, os.Stdin)
if err != nil {
return err
}
err = f.Close()
if err != nil {
return err
}
2019-04-30 01:09:37 +02:00
fnames = []string{f.Name()}
2018-10-16 21:23:01 +02:00
defer func() {
2019-04-30 01:09:37 +02:00
err = os.Remove(fnames[0])
2018-10-16 21:23:01 +02:00
if err != nil {
2019-07-17 22:33:02 +02:00
log.Error(err)
2018-10-16 21:23:01 +02:00
}
}()
} else {
2019-04-30 01:09:37 +02:00
fnames = append([]string{c.Args().First()}, c.Args().Tail()...)
2018-10-16 21:23:01 +02:00
}
2019-04-30 01:09:37 +02:00
if len(fnames) == 0 {
2018-10-16 21:23:01 +02:00
return errors.New("must specify file: croc send [filename]")
}
2019-04-30 01:09:37 +02:00
2019-07-18 01:23:50 +02:00
if len(crocOptions.SharedSecret) == 0 {
2018-10-16 21:23:01 +02:00
// generate code phrase
2019-07-18 01:23:50 +02:00
crocOptions.SharedSecret = utils.GetRandomName()
2018-10-16 21:23:01 +02:00
}
2019-04-30 01:09:37 +02:00
haveFolder := false
paths := []string{}
for _, fname := range fnames {
stat, err := os.Stat(fname)
2018-10-16 21:23:01 +02:00
if err != nil {
return err
}
2019-04-30 01:09:37 +02:00
if stat.IsDir() {
haveFolder = true
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))
}
2018-10-16 21:23:01 +02:00
}
2019-07-18 01:23:50 +02:00
2019-07-18 00:19:32 +02:00
cr, err := croc.New(crocOptions)
2019-04-30 01:09:37 +02:00
if err != nil {
return
}
2019-04-30 01:09:37 +02:00
2019-07-18 00:19:32 +02:00
// save the config
if c.GlobalBool("remember") {
log.Debug("saving config file")
var bConfig []byte
2019-07-18 01:23:50 +02:00
// if the code wasn't set, don't save it
if c.String("code") == "" {
crocOptions.SharedSecret = ""
}
2019-07-18 00:19:32 +02:00
bConfig, err = json.MarshalIndent(crocOptions, "", " ")
if err != nil {
log.Error(err)
return
}
err = ioutil.WriteFile(configFile, bConfig, 0644)
if err != nil {
log.Error(err)
return
}
log.Debugf("wrote %s", configFile)
}
2019-04-30 01:09:37 +02:00
err = cr.Send(croc.TransferOptions{
PathToFiles: paths,
KeepPathInRemote: haveFolder,
})
return
2018-10-16 21:23:01 +02:00
}
2019-04-30 01:09:37 +02:00
func receive(c *cli.Context) (err error) {
2019-07-18 02:16:50 +02:00
crocOptions := croc.Options{
SharedSecret: c.String("code"),
IsSender: false,
Debug: c.GlobalBool("debug"),
NoPrompt: c.GlobalBool("yes"),
RelayAddress: c.GlobalString("relay"),
Stdout: c.GlobalBool("stdout"),
2018-10-16 21:23:01 +02:00
}
if c.Args().First() != "" {
2019-07-18 02:16:50 +02:00
crocOptions.SharedSecret = c.Args().First()
2019-04-30 01:09:37 +02:00
}
2019-07-18 02:16:50 +02:00
// load options here
if c.GlobalBool("debug") {
log.SetLevel("debug")
log.Debug("debug mode on")
}
configFile, err := getConfigDir()
if err != nil {
log.Error(err)
return
}
configFile = path.Join(configFile, "receive.json")
b, errOpen := ioutil.ReadFile(configFile)
if errOpen == nil && !c.GlobalBool("remember") {
var rememberedOptions croc.Options
err = json.Unmarshal(b, &rememberedOptions)
if err != nil {
log.Error(err)
return
}
// update anything that isn't explicitly set
if !c.GlobalIsSet("relay") {
crocOptions.RelayAddress = rememberedOptions.RelayAddress
}
if crocOptions.SharedSecret == "" {
crocOptions.SharedSecret = rememberedOptions.SharedSecret
}
}
if crocOptions.SharedSecret == "" {
crocOptions.SharedSecret = utils.GetInput("Enter receive code: ")
2018-10-16 21:23:01 +02:00
}
2018-10-22 15:36:36 +02:00
if c.GlobalString("out") != "" {
os.Chdir(c.GlobalString("out"))
}
2019-04-30 01:09:37 +02:00
2019-07-18 02:16:50 +02:00
cr, err := croc.New(crocOptions)
2019-04-30 01:09:37 +02:00
if err != nil {
return
2018-10-19 19:18:49 +02:00
}
2019-04-30 01:09:37 +02:00
err = cr.Receive()
return
2018-10-16 21:23:01 +02:00
}
2019-04-30 06:25:30 +02:00
func relay(c *cli.Context) (err error) {
2019-05-02 21:08:23 +02:00
debugString := "info"
2019-04-30 06:25:30 +02:00
if c.GlobalBool("debug") {
debugString = "debug"
}
2019-05-01 21:48:09 +02:00
ports := strings.Split(c.String("ports"), ",")
2019-05-01 01:19:10 +02:00
tcpPorts := strings.Join(ports[1:], ",")
2019-04-30 06:25:30 +02:00
for i, port := range ports {
if i == 0 {
continue
}
go func(portStr string) {
2019-05-01 01:26:32 +02:00
err = tcp.Run(debugString, portStr)
2019-04-30 06:25:30 +02:00
if err != nil {
panic(err)
}
}(port)
}
return tcp.Run(debugString, ports[0], tcpPorts)
2019-04-30 06:25:30 +02:00
}