From 030ebca2c1adc74036914bab5c03d79a62a331fa Mon Sep 17 00:00:00 2001 From: Justin Hawkins Date: Sun, 16 Jan 2022 19:46:29 +1030 Subject: [PATCH] Make it possible to set authtoken via ENV --- .vscode/settings.json | 1 + client.go | 42 ++++++++++++------- main.go | 93 ++++++++++++++++++++++++++++++++++++------- server.go | 9 +++-- 4 files changed, 112 insertions(+), 33 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 63560cc..45e78ba 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "cSpell.words": [ + "isatty", "netgiv", "pflag" ] diff --git a/client.go b/client.go index 98be0b4..20bffe1 100644 --- a/client.go +++ b/client.go @@ -9,6 +9,7 @@ import ( "io" "net" "os" + "time" log "github.com/sirupsen/logrus" @@ -17,27 +18,40 @@ import ( ) type Client struct { - address string - port int - list bool - send bool - receive bool + address string + port int + list bool + send bool + receive bool + authToken string } func (c *Client) Connect() error { address := fmt.Sprintf("%s:%d", c.address, c.port) - serverAddress, _ := net.ResolveTCPAddr("tcp", address) + d := net.Dialer{Timeout: 5 * time.Second} - conn, err := net.DialTCP("tcp", nil, serverAddress) + conn, err := d.Dial("tcp", address) + + // serverAddress, err := net.ResolveTCPAddr("tcp", address) + // if err != nil { + // return err + // } + + // conn, err := d.Dial("tcp", serverAddress) if err != nil { - return errors.New("problem connecting to server, is it running?\n") + return fmt.Errorf("problem connecting to server, is it running?: %v", err) } defer conn.Close() log.Printf("Connection on %s\n", address) - sharedKey := secure.Handshake(conn) + tcpConn, ok := conn.(*net.TCPConn) + if !ok { + log.Fatal("could not assert") + } + + sharedKey := secure.Handshake(tcpConn) secureConnection := secure.SecureConnection{Conn: conn, SharedKey: sharedKey, Buffer: &bytes.Buffer{}} enc := gob.NewEncoder(&secureConnection) @@ -46,7 +60,7 @@ func (c *Client) Connect() error { if c.list { log.Printf("requesting file list") - err := connectToServer(secure.OperationTypeList, enc, dec) + err := c.connectToServer(secure.OperationTypeList, enc, dec) if err != nil { return fmt.Errorf("could not connect and auth: %v", err) } @@ -69,7 +83,7 @@ func (c *Client) Connect() error { } else if c.receive { log.Printf("receiving a file") - err := connectToServer(secure.OperationTypeReceive, enc, dec) + err := c.connectToServer(secure.OperationTypeReceive, enc, dec) if err != nil { return fmt.Errorf("could not connect and auth: %v", err) } @@ -111,7 +125,7 @@ func (c *Client) Connect() error { } else if c.send { // send mode - err := connectToServer(secure.OperationTypeSend, enc, dec) + err := c.connectToServer(secure.OperationTypeSend, enc, dec) if err != nil { return fmt.Errorf("could not connect and auth: %v", err) } @@ -167,14 +181,14 @@ func (c *Client) Connect() error { } -func connectToServer(op secure.OperationTypeEnum, enc *gob.Encoder, dec *gob.Decoder) error { +func (c *Client) connectToServer(op secure.OperationTypeEnum, enc *gob.Encoder, dec *gob.Decoder) error { // list mode startPacket := secure.PacketStartRequest{ OperationType: op, ClientName: "", ProtocolVersion: "1.0", - AuthToken: "dummy", + AuthToken: c.authToken, } err := enc.Encode(startPacket) if err != nil { diff --git a/main.go b/main.go index e0bfc6a..7b16532 100644 --- a/main.go +++ b/main.go @@ -14,29 +14,95 @@ import ( func main() { // log.SetFlags(log.Lshortfile) - flag.Int("port", 4912, "Port to run server/client on.") - addr := flag.String("a", "127.0.0.1", "address to connect to.") - isServer := flag.Bool("s", false, "Set if running the server.") + // flag.Int("port", 4912, "Port to run server/client on.") + // addr := flag.String("a", "127.0.0.1", "address to connect to.") + isServer := flag.Bool("s", false, "Run netgiv in server mode") + + // client mode flags isList := flag.Bool("l", false, "Set if requesting a list") - isSend := flag.Bool("c", false, "Set if sending a file (copy)") - isReceive := flag.Bool("p", false, "Set if receiving a file (paste)") + isSend := flag.Bool("c", false, "sending stdin to netgiv server (copy)") + isReceive := flag.Bool("p", false, "receive file from netgiv server to stdout (paste)") + flag.String("address", "", "IP address/hostname of the netgiv server") + + helpConfig := flag.Bool("help-config", false, "Show help on netgiv configuration") + + // common flags + flag.String("authtoken", "", "Authentication token") + flag.Int("port", 0, "Port") flag.Parse() + viper.AddConfigPath("$HOME/.netgiv/") // call multiple times to add many search paths + viper.SetConfigType("yaml") + viper.SetDefault("port", 4512) + if err := viper.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); ok { + // no config file maybe that's ok + panic(err) + } else { + // Config file was found but another error was produced + log.Fatal(err) + } + } + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) pflag.Parse() viper.BindPFlags(pflag.CommandLine) + viper.SetEnvPrefix("NETGIV") + viper.BindEnv("authtoken") + + // pull the various things into local variables port := viper.GetInt("port") // retrieve value from viper + authtoken := viper.GetString("authtoken") + + if authtoken == "" { + log.Fatal("authtoken must be set") + } + + address := viper.GetString("address") + if !*isServer && address == "" { + log.Fatal("an address must be provided on the command line, or configuration") + } + + flag.Usage = func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args[0]) + flag.PrintDefaults() + fmt.Printf("\nIf stdin or stdout is a pipe, %s will automatically choose an appropriate\n", os.Args[0]) + fmt.Printf("copy (-c) or paste (-p) mode\n") + } + + if *helpConfig { + fmt.Print( + `netgiv can be configured by command line parameters (see --help) but it will +often be convenient to create a config file. The config file is in yaml format, +and should be stored in $HOME/.netgiv/config.yaml. + +For both client and server, you will want to set the 'authtoken' key (they must +match). You'll want to also set the 'port' key if you would like to run netgiv +on a non-standard port (the default is 4512). + +On the client you will probably want to set the 'address' key, so that your client +knows where to find the netgiv server. This key is ignored when running in server +mode. + +Example: + +port: 5412 +authtoken: verysecretvaluehere +address: 10.1.12.20 +`) + os.Exit(1) + + } if *isServer { - - log.Printf("Server running on %d\n", port) - s := Server{port: port} + s := Server{port: port, authToken: authtoken} s.Run() } else { + if !*isList && !*isSend && !*isReceive { // try to work out the intent based on whether or not stdin/stdout // are ttys @@ -45,21 +111,18 @@ func main() { if stdinTTY && !stdoutTTY { *isReceive = true - } else if !stdinTTY && stdoutTTY { *isSend = true } else if !stdinTTY && !stdoutTTY { log.Fatal("I can't cope with both stdin and stdout being pipes") + } else { + flag.Usage() + os.Exit(1) } } - if !*isList && !*isSend && !*isReceive { - // could default to list? - *isList = true - } - - c := Client{port: port, address: *addr, list: *isList, send: *isSend, receive: *isReceive} + c := Client{port: port, address: address, list: *isList, send: *isSend, receive: *isReceive, authToken: authtoken} err := c.Connect() if err != nil { fmt.Print(err) diff --git a/server.go b/server.go index 4a63b71..b73bef2 100644 --- a/server.go +++ b/server.go @@ -20,7 +20,8 @@ import ( ) type Server struct { - port int + port int + authToken string } // An NGF is a Netgiv File @@ -71,11 +72,11 @@ func (s *Server) Run() { fmt.Print(err) } - go handleConnection(conn) + go s.handleConnection(conn) } } -func handleConnection(conn *net.TCPConn) { +func (s *Server) handleConnection(conn *net.TCPConn) { defer conn.Close() conn.SetDeadline(time.Now().Add(time.Second * 5)) @@ -113,7 +114,7 @@ func handleConnection(conn *net.TCPConn) { return } - if start.AuthToken != "dummy2" { + if start.AuthToken != s.authToken { log.Print("bad authtoken") startResponse.Response = secure.PacketStartResponseEnumBadAuthToken enc.Encode(startResponse)