Use raw TCP instead of HTTP to transfer files
This commit is contained in:
		
							
								
								
									
										36
									
								
								config.go
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								config.go
									
									
									
									
									
								
							@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"github.com/rs/zerolog/log"
 | 
						"github.com/rs/zerolog/log"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
@@ -25,6 +26,24 @@ func NewConfig(actionType string, actionData string) *Config {
 | 
				
			|||||||
	return &Config{ActionType: actionType, ActionData: actionData}
 | 
						return &Config{ActionType: actionType, ActionData: actionData}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (config *Config) Validate()  {
 | 
				
			||||||
 | 
						// Parse URL in config
 | 
				
			||||||
 | 
						urlParser, err := url.Parse(config.ActionData)
 | 
				
			||||||
 | 
						// If there was an error parsing
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// Alert user of invalid url
 | 
				
			||||||
 | 
							log.Fatal().Err(err).Msg("Invalid URL")
 | 
				
			||||||
 | 
						// If scheme is not detected
 | 
				
			||||||
 | 
						} else if urlParser.Scheme == "" {
 | 
				
			||||||
 | 
							// Alert user of invalid scheme
 | 
				
			||||||
 | 
							log.Fatal().Msg("Invalid URL scheme")
 | 
				
			||||||
 | 
						// If host is not detected
 | 
				
			||||||
 | 
						} else if urlParser.Host == "" {
 | 
				
			||||||
 | 
							// Alert user of invalid host
 | 
				
			||||||
 | 
							log.Fatal().Msg("Invalid URL host")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create config file
 | 
					// Create config file
 | 
				
			||||||
func (config *Config) CreateFile(dir string) {
 | 
					func (config *Config) CreateFile(dir string) {
 | 
				
			||||||
	// Use ConsoleWriter logger
 | 
						// Use ConsoleWriter logger
 | 
				
			||||||
@@ -137,8 +156,23 @@ func (config *Config) ExecuteAction(srcDir string, destDir string) {
 | 
				
			|||||||
		if err != nil { log.Fatal().Err(err).Msg("Error copying data to file") }
 | 
							if err != nil { log.Fatal().Err(err).Msg("Error copying data to file") }
 | 
				
			||||||
	// If action is url
 | 
						// If action is url
 | 
				
			||||||
	} else if config.ActionType == "url" {
 | 
						} else if config.ActionType == "url" {
 | 
				
			||||||
 | 
							// Parse received URL
 | 
				
			||||||
 | 
							urlParser, err := url.Parse(config.ActionData)
 | 
				
			||||||
 | 
							// If there was an error parsing
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								// Alert user of invalid url
 | 
				
			||||||
 | 
								log.Fatal().Err(err).Msg("Invalid URL")
 | 
				
			||||||
 | 
							// If scheme is not detected
 | 
				
			||||||
 | 
							} else if urlParser.Scheme == "" {
 | 
				
			||||||
 | 
								// Alert user of invalid scheme
 | 
				
			||||||
 | 
								log.Fatal().Msg("Invalid URL scheme")
 | 
				
			||||||
 | 
							// If host is not detected
 | 
				
			||||||
 | 
							} else if urlParser.Host == "" {
 | 
				
			||||||
 | 
								// Alert user of invalid host
 | 
				
			||||||
 | 
								log.Fatal().Msg("Invalid URL host")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		// Attempt to open URL in browser
 | 
							// Attempt to open URL in browser
 | 
				
			||||||
		err := browser.OpenURL(config.ActionData)
 | 
							err = browser.OpenURL(config.ActionData)
 | 
				
			||||||
		if err != nil { log.Fatal().Err(err).Msg("Error opening browser") }
 | 
							if err != nil { log.Fatal().Err(err).Msg("Error opening browser") }
 | 
				
			||||||
	// If action is dir
 | 
						// If action is dir
 | 
				
			||||||
	} else if config.ActionType == "dir" {
 | 
						} else if config.ActionType == "dir" {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										273
									
								
								files.go
									
									
									
									
									
								
							
							
						
						
									
										273
									
								
								files.go
									
									
									
									
									
								
							@@ -1,19 +1,20 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"bufio"
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/rs/zerolog"
 | 
						"github.com/rs/zerolog"
 | 
				
			||||||
	"github.com/rs/zerolog/log"
 | 
						"github.com/rs/zerolog/log"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Save encrypted key to file
 | 
					// Save encrypted key to file
 | 
				
			||||||
@@ -34,147 +35,179 @@ func SaveEncryptedKey(encryptedKey []byte, filePath string) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Create HTTP server to transmit files
 | 
					// Create HTTP server to transmit files
 | 
				
			||||||
func SendFiles(dir string) {
 | 
					func SendFiles(dir string) {
 | 
				
			||||||
	// Use ConsoleWriter logger
 | 
						// Use ConsoleWriter logger with normal FatalHook
 | 
				
			||||||
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
 | 
						log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
 | 
				
			||||||
	// Instantiate http.Server struct
 | 
						// Create TCP listener on port 9898
 | 
				
			||||||
	srv := &http.Server{}
 | 
					 | 
				
			||||||
	// Listen on all ipv4 addresses on port 9898
 | 
					 | 
				
			||||||
	listener, err := net.Listen("tcp", ":9898")
 | 
						listener, err := net.Listen("tcp", ":9898")
 | 
				
			||||||
	if err != nil { log.Fatal().Err(err).Msg("Error starting listener") }
 | 
						if err != nil { log.Fatal().Err(err).Msg("Error starting listener") }
 | 
				
			||||||
 | 
						// Accept connection on listener
 | 
				
			||||||
	// If client connects to /:filePath
 | 
						connection, err := listener.Accept()
 | 
				
			||||||
	http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
 | 
						if err != nil { log.Fatal().Err(err).Msg("Error accepting connection") }
 | 
				
			||||||
		// Set file to first path components of URL, excluding first /
 | 
						// Close connection at the end of this function
 | 
				
			||||||
		file := req.URL.Path[1:]
 | 
						defer connection.Close()
 | 
				
			||||||
		// Read file at specified location
 | 
						// Create for loop to listen for messages on connection
 | 
				
			||||||
		fileData, err := ioutil.ReadFile(dir + "/" + file)
 | 
						connectionLoop: for {
 | 
				
			||||||
		// If there was an error reading
 | 
							// Use ConsoleWriter logger with TCPFatalHook
 | 
				
			||||||
		if err != nil {
 | 
							log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(TCPFatalHook{conn: connection})
 | 
				
			||||||
			// Warn user of error
 | 
							// Attempt to read new message on connection
 | 
				
			||||||
			log.Warn().Err(err).Msg("Error reading file")
 | 
							data, err := bufio.NewReader(connection).ReadString('\n')
 | 
				
			||||||
		// Otherwise
 | 
							// If no message detected, try again
 | 
				
			||||||
		} else {
 | 
							if err != nil && err.Error() == "EOF" { continue }
 | 
				
			||||||
			// Inform user client has requested a file
 | 
							// If non-EOF error, fatally log
 | 
				
			||||||
			log.Info().Str("file", file).Msg("GET File")
 | 
							if err != nil { log.Fatal().Err(err).Msg("Error reading data") }
 | 
				
			||||||
		}
 | 
							// Process received data
 | 
				
			||||||
		// Write file to ResponseWriter
 | 
							processedData := strings.Split(strings.TrimSpace(data), ";")
 | 
				
			||||||
		_, err = fmt.Fprint(res, string(fileData))
 | 
							// If processedData is empty, alert the user of invalid data
 | 
				
			||||||
		if err != nil { log.Fatal().Err(err).Msg("Error writing response") }
 | 
							if len(processedData) < 1 { log.Fatal().Str("data", data).Msg("Received data invalid") }
 | 
				
			||||||
	})
 | 
							switch processedData[0] {
 | 
				
			||||||
 | 
							case "key":
 | 
				
			||||||
	// If client connects to /index
 | 
								// Inform user client has requested key
 | 
				
			||||||
	http.HandleFunc("/index", func(res http.ResponseWriter, req *http.Request) {
 | 
								log.Info().Msg("Key requested")
 | 
				
			||||||
		// Inform user a client has requested the file index
 | 
								// Read saved key
 | 
				
			||||||
		log.Info().Msg("GET Index")
 | 
								key, err := ioutil.ReadFile(dir + "/key.aes")
 | 
				
			||||||
		// Get directory listing
 | 
								if err != nil { log.Fatal().Err(err).Msg("Error reading key") }
 | 
				
			||||||
		dirListing, err := ioutil.ReadDir(dir)
 | 
								// Write saved key to ResponseWriter
 | 
				
			||||||
		if err != nil { log.Fatal().Err(err).Msg("Error reading directory") }
 | 
								_, err = fmt.Fprintln(connection, "OK;" + hex.EncodeToString(key) + ";")
 | 
				
			||||||
		// Create new slice to house filenames for index
 | 
								if err != nil { log.Fatal().Err(err).Msg("Error writing response") }
 | 
				
			||||||
		var indexSlice []string
 | 
							case "index":
 | 
				
			||||||
		// For each file in listing
 | 
								// Inform user a client has requested the file index
 | 
				
			||||||
		for _, file := range dirListing {
 | 
								log.Info().Msg("Index requested")
 | 
				
			||||||
			// If the file is not the key
 | 
								// Get directory listing
 | 
				
			||||||
			if !strings.Contains(file.Name(), "key.aes") {
 | 
								dirListing, err := ioutil.ReadDir(dir)
 | 
				
			||||||
				// Append the file path to indexSlice
 | 
								if err != nil { log.Fatal().Err(err).Msg("Error reading directory") }
 | 
				
			||||||
				indexSlice = append(indexSlice, file.Name())
 | 
								// Create new slice to house filenames for index
 | 
				
			||||||
 | 
								var indexSlice []string
 | 
				
			||||||
 | 
								// For each file in listing
 | 
				
			||||||
 | 
								for _, file := range dirListing {
 | 
				
			||||||
 | 
									// If the file is not the key
 | 
				
			||||||
 | 
									if !strings.Contains(file.Name(), "key.aes") {
 | 
				
			||||||
 | 
										// Append the file path to indexSlice
 | 
				
			||||||
 | 
										indexSlice = append(indexSlice, file.Name())
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								// Join index slice into string
 | 
				
			||||||
 | 
								indexStr := strings.Join(indexSlice, "|")
 | 
				
			||||||
 | 
								// Write index to ResponseWriter
 | 
				
			||||||
 | 
								_, err = fmt.Fprintln(connection, "OK;" + indexStr + ";")
 | 
				
			||||||
 | 
								if err != nil { log.Fatal().Err(err).Msg("Error writing response") }
 | 
				
			||||||
 | 
							case "file":
 | 
				
			||||||
 | 
								// If processedData only has one entry
 | 
				
			||||||
 | 
								if len(processedData) == 1 {
 | 
				
			||||||
 | 
									// Warn user of unexpected end of line
 | 
				
			||||||
 | 
									log.Warn().Err(errors.New("unexpected eol")).Msg("Invalid file request")
 | 
				
			||||||
 | 
									// Send error to connection
 | 
				
			||||||
 | 
									_, _ = fmt.Fprintln(connection, "ERR;")
 | 
				
			||||||
 | 
									// Break out of switch
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Set file to first path components of URL, excluding first /
 | 
				
			||||||
 | 
								file := processedData[1]
 | 
				
			||||||
 | 
								// Read file at specified location
 | 
				
			||||||
 | 
								fileData, err := ioutil.ReadFile(dir + "/" + file)
 | 
				
			||||||
 | 
								// If there was an error reading
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									// Warn user of error
 | 
				
			||||||
 | 
									log.Warn().Err(err).Msg("Error reading file")
 | 
				
			||||||
 | 
									// Otherwise
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									// Inform user client has requested a file
 | 
				
			||||||
 | 
									log.Info().Str("file", file).Msg("File requested")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Write file as hex to connection
 | 
				
			||||||
 | 
								_, err = fmt.Fprintln(connection, "OK;" + hex.EncodeToString(fileData) + ";")
 | 
				
			||||||
 | 
								if err != nil { log.Fatal().Err(err).Msg("Error writing response") }
 | 
				
			||||||
 | 
							case "stop":
 | 
				
			||||||
 | 
								// Alert user that stop signal has been received
 | 
				
			||||||
 | 
								log.Info().Msg("Received stop signal")
 | 
				
			||||||
 | 
								// Print ok message to connection
 | 
				
			||||||
 | 
								_, _ = fmt.Fprintln(connection, "OK;")
 | 
				
			||||||
 | 
								// Break out of connectionLoop
 | 
				
			||||||
 | 
								break connectionLoop
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Join index slice into string
 | 
						}
 | 
				
			||||||
		indexStr := strings.Join(indexSlice, ";")
 | 
					}
 | 
				
			||||||
		// Write index to ResponseWriter
 | 
					 | 
				
			||||||
		_, err = fmt.Fprint(res, indexStr)
 | 
					 | 
				
			||||||
		if err != nil { log.Fatal().Err(err).Msg("Error writing response") }
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If client connects to /key
 | 
					func ConnectToSender(senderAddr string) net.Conn {
 | 
				
			||||||
	http.HandleFunc("/key", func(res http.ResponseWriter, req *http.Request) {
 | 
						// Get server address by getting the IP without the port, and appending :9898
 | 
				
			||||||
		// Inform user a client has requested the key
 | 
						serverAddr := strings.Split(senderAddr, ":")[0] + ":9898"
 | 
				
			||||||
		log.Info().Msg("GET Key")
 | 
						// Create error variable
 | 
				
			||||||
		// Read saved key
 | 
						var err error
 | 
				
			||||||
		key, err := ioutil.ReadFile(dir + "/key.aes")
 | 
						// Create connection variable
 | 
				
			||||||
		if err != nil { log.Fatal().Err(err).Msg("Error reading key") }
 | 
						var connection net.Conn
 | 
				
			||||||
		// Write saved key to ResponseWriter
 | 
						// Until break
 | 
				
			||||||
		_, err = fmt.Fprint(res, string(key))
 | 
						for {
 | 
				
			||||||
		if err != nil { log.Fatal().Err(err).Msg("Error writing response") }
 | 
							// Try connecting to sender
 | 
				
			||||||
	})
 | 
							connection, err = net.Dial("tcp", serverAddr)
 | 
				
			||||||
 | 
							// If connection refused
 | 
				
			||||||
	// If client connects to /stop
 | 
							if err != nil && strings.Contains(err.Error(), "connection refused") {
 | 
				
			||||||
	http.HandleFunc("/stop", func(res http.ResponseWriter, req *http.Request) {
 | 
								// Continue loop (retry)
 | 
				
			||||||
		// Inform user a client has requested server shutdown
 | 
								continue
 | 
				
			||||||
		log.Info().Msg("GET Stop")
 | 
								// If error other than connection refused
 | 
				
			||||||
		log.Info().Msg("Stop signal received")
 | 
							} else if err != nil {
 | 
				
			||||||
		// Shutdown server and send to empty context
 | 
								// Fatally log
 | 
				
			||||||
		err := srv.Shutdown(context.Background())
 | 
								log.Fatal().Err(err).Msg("Error connecting to sender")
 | 
				
			||||||
		if err != nil { log.Fatal().Err(err).Msg("Error stopping server") }
 | 
								// If no error
 | 
				
			||||||
	})
 | 
							} else {
 | 
				
			||||||
 | 
								// Break out of loop
 | 
				
			||||||
	// Start HTTP Server
 | 
								break
 | 
				
			||||||
	_ = srv.Serve(listener)
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Returned created connection
 | 
				
			||||||
 | 
						return connection
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Get files from sender
 | 
					// Get files from sender
 | 
				
			||||||
func RecvFiles(senderAddr string) {
 | 
					func RecvFiles(connection net.Conn) {
 | 
				
			||||||
	// Use ConsoleWriter logger
 | 
						// Use ConsoleWriter logger
 | 
				
			||||||
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
 | 
						log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
 | 
				
			||||||
	// Get server address by getting the IP without the port, prepending http:// and appending :9898
 | 
						// Request index from sender
 | 
				
			||||||
	serverAddr := "http://" + strings.Split(senderAddr, ":")[0] + ":9898"
 | 
						_, err := fmt.Fprintln(connection, "index;")
 | 
				
			||||||
	var response *http.Response
 | 
						if err != nil { log.Fatal().Err(err).Msg("Error sending index request") }
 | 
				
			||||||
	// GET /index on sender's HTTP server
 | 
						// Read received message
 | 
				
			||||||
	response, err := http.Get(serverAddr + "/index")
 | 
						message, err := bufio.NewReader(connection).ReadString('\n')
 | 
				
			||||||
	// If error occurred, retry every 500ms
 | 
						if err != nil { log.Fatal().Err(err).Msg("Error getting index") }
 | 
				
			||||||
	if err != nil {
 | 
						// Process received message
 | 
				
			||||||
		// Set index failed to true
 | 
						procMessage := strings.Split(strings.TrimSpace(message), ";")
 | 
				
			||||||
		indexGetFailed := true
 | 
						// If non-ok code returned, fatally log
 | 
				
			||||||
		for indexGetFailed {
 | 
						if procMessage[0] != "OK" { log.Fatal().Err(err).Msg("Sender reported error") }
 | 
				
			||||||
			// GET /index on sender's HTTP server
 | 
						// Get index from message
 | 
				
			||||||
			response, err = http.Get(serverAddr + "/index")
 | 
						index := strings.Split(strings.TrimSpace(procMessage[1]), "|")
 | 
				
			||||||
			// If no error, set index failed to false
 | 
					 | 
				
			||||||
			if err == nil { indexGetFailed = false }
 | 
					 | 
				
			||||||
			// Wait 500ms
 | 
					 | 
				
			||||||
			time.Sleep(500*time.Millisecond)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// Close response body at the end of this function
 | 
					 | 
				
			||||||
	defer response.Body.Close()
 | 
					 | 
				
			||||||
	// Create index slice for storage of file index
 | 
					 | 
				
			||||||
	var index []string
 | 
					 | 
				
			||||||
	// If server responded with 200 OK
 | 
					 | 
				
			||||||
	if response.StatusCode == http.StatusOK {
 | 
					 | 
				
			||||||
		// Read response body
 | 
					 | 
				
			||||||
		body, err := ioutil.ReadAll(response.Body)
 | 
					 | 
				
			||||||
		if err != nil { log.Fatal().Err(err).Msg("Error reading HTTP response") }
 | 
					 | 
				
			||||||
		// Get string from body
 | 
					 | 
				
			||||||
		bodyStr := string(body)
 | 
					 | 
				
			||||||
		// Split string to form index
 | 
					 | 
				
			||||||
		index = strings.Split(bodyStr, ";")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// For each file in the index
 | 
					 | 
				
			||||||
	for _, file := range index {
 | 
						for _, file := range index {
 | 
				
			||||||
		// GET current file in index
 | 
							// Get current file in index
 | 
				
			||||||
		response, err := http.Get(serverAddr + "/" + filepath.Base(file))
 | 
							_, err = fmt.Fprintln(connection, "file;" + file + ";")
 | 
				
			||||||
 | 
							if err != nil { log.Fatal().Err(err).Msg("Error sending file request") }
 | 
				
			||||||
 | 
							// Read received message
 | 
				
			||||||
 | 
							message, err := bufio.NewReader(connection).ReadString('\n')
 | 
				
			||||||
		if err != nil { log.Fatal().Err(err).Msg("Error getting file") }
 | 
							if err != nil { log.Fatal().Err(err).Msg("Error getting file") }
 | 
				
			||||||
		// If server responded with 200 OK
 | 
							// Process received message
 | 
				
			||||||
		if response.StatusCode == http.StatusOK {
 | 
							procMessage := strings.Split(message, ";")
 | 
				
			||||||
 | 
							// If non-ok code returned
 | 
				
			||||||
 | 
							if procMessage[0] != "OK" {
 | 
				
			||||||
 | 
								// fatally log
 | 
				
			||||||
 | 
								log.Fatal().Err(err).Msg("Sender reported error")
 | 
				
			||||||
 | 
							// Otherwise
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
			// Create new file at index filepath
 | 
								// Create new file at index filepath
 | 
				
			||||||
			newFile, err := os.Create(opensendDir + "/" + file)
 | 
								newFile, err := os.Create(opensendDir + "/" + file)
 | 
				
			||||||
			if err != nil { log.Fatal().Err(err).Msg("Error creating file") }
 | 
								if err != nil { log.Fatal().Err(err).Msg("Error creating file") }
 | 
				
			||||||
 | 
								// Decode file data from hex string
 | 
				
			||||||
 | 
								fileData, err := hex.DecodeString(strings.TrimSpace(procMessage[1]))
 | 
				
			||||||
 | 
								if err != nil { log.Fatal().Err(err).Msg("Error decoding hex") }
 | 
				
			||||||
			// Copy response body to new file
 | 
								// Copy response body to new file
 | 
				
			||||||
			bytesWritten, err := io.Copy(newFile, response.Body)
 | 
								bytesWritten, err := io.Copy(newFile, bytes.NewBuffer(fileData))
 | 
				
			||||||
			if err != nil { log.Fatal().Err(err).Msg("Error writing to file") }
 | 
								if err != nil { log.Fatal().Err(err).Msg("Error writing to file") }
 | 
				
			||||||
			// Log bytes written
 | 
								// Log bytes written
 | 
				
			||||||
			log.Info().Str("file", filepath.Base(file)).Msg("Wrote " + strconv.Itoa(int(bytesWritten)) + " bytes")
 | 
								log.Info().Str("file", filepath.Base(file)).Msg("Wrote " + strconv.Itoa(int(bytesWritten)) + " bytes")
 | 
				
			||||||
			// Close new file
 | 
								// Close new file
 | 
				
			||||||
			newFile.Close()
 | 
								newFile.Close()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Close response body
 | 
					 | 
				
			||||||
		response.Body.Close()
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Send stop signal to sender's HTTP server
 | 
					// Send stop signal to sender
 | 
				
			||||||
func SendSrvStopSignal(senderAddr string) {
 | 
					func SendSrvStopSignal(connection net.Conn) {
 | 
				
			||||||
	// Get server address by getting the IP without the port, prepending http:// and appending :9898
 | 
						// Send stop signal to connection
 | 
				
			||||||
	serverAddr := "http://" + strings.Split(senderAddr, ":")[0] + ":9898"
 | 
						_, _ = fmt.Fprintln(connection, "stop;")
 | 
				
			||||||
	// GET /stop on sender's HTTP servers ignoring any errors
 | 
						// Close connection
 | 
				
			||||||
	_, _ = http.Get(serverAddr + "/stop")
 | 
						_ = connection.Close()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								keyCrypto.go
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								keyCrypto.go
									
									
									
									
									
								
							@@ -1,13 +1,15 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
	"crypto/rand"
 | 
						"crypto/rand"
 | 
				
			||||||
	"crypto/rsa"
 | 
						"crypto/rsa"
 | 
				
			||||||
	"crypto/sha256"
 | 
						"crypto/sha256"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"github.com/rs/zerolog"
 | 
						"github.com/rs/zerolog"
 | 
				
			||||||
	"github.com/rs/zerolog/log"
 | 
						"github.com/rs/zerolog/log"
 | 
				
			||||||
	"io/ioutil"
 | 
						"net"
 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -26,27 +28,28 @@ func GenerateRSAKeypair() (*rsa.PrivateKey, *rsa.PublicKey) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Get public key from sender
 | 
					// Get public key from sender
 | 
				
			||||||
func GetKey(senderAddr string) []byte {
 | 
					func GetKey(connection net.Conn) []byte {
 | 
				
			||||||
	// Use ConsoleWriter logger
 | 
						// Use ConsoleWriter logger
 | 
				
			||||||
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
 | 
						log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
 | 
				
			||||||
	// Get server address by getting the IP without the port, prepending http:// and appending :9898
 | 
						// Send key request to connection
 | 
				
			||||||
	serverAddr := "http://" + strings.Split(senderAddr, ":")[0] + ":9898"
 | 
						_, err := fmt.Fprintln(connection, "key;")
 | 
				
			||||||
	// GET /key on the sender's HTTP server
 | 
						if err != nil { log.Fatal().Err(err).Msg("Error sending key request") }
 | 
				
			||||||
	response, err := http.Get(serverAddr + "/key")
 | 
						// Read received message
 | 
				
			||||||
 | 
						message, err := bufio.NewReader(connection).ReadString('\n')
 | 
				
			||||||
	if err != nil { log.Fatal().Err(err).Msg("Error getting key") }
 | 
						if err != nil { log.Fatal().Err(err).Msg("Error getting key") }
 | 
				
			||||||
	// Close response body at the end of this function
 | 
						// Process received message
 | 
				
			||||||
	defer response.Body.Close()
 | 
						procMessage := strings.Split(strings.TrimSpace(message), ";")
 | 
				
			||||||
	// If server responded with 200 OK
 | 
						// If ok code returned
 | 
				
			||||||
	if response.StatusCode == http.StatusOK {
 | 
						if procMessage[0] == "OK" {
 | 
				
			||||||
		// Read response body into key
 | 
							// Decode received hex string into key
 | 
				
			||||||
		key, err := ioutil.ReadAll(response.Body)
 | 
							key, err := hex.DecodeString(procMessage[1])
 | 
				
			||||||
		if err != nil { log.Fatal().Err(err).Msg("Error reading HTTP response") }
 | 
							if err != nil { log.Fatal().Err(err).Msg("Error reading key") }
 | 
				
			||||||
		// Return key
 | 
							// Return key
 | 
				
			||||||
		return key
 | 
							return key
 | 
				
			||||||
	// Otherwise
 | 
						// Otherwise
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// Fatally log status code
 | 
							// Fatally log
 | 
				
			||||||
		if err != nil { log.Fatal().Int("code", response.StatusCode).Msg("HTTP Error Response Code Received") }
 | 
							if err != nil { log.Fatal().Msg("Server reported error") }
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Return nil if all else fails
 | 
						// Return nil if all else fails
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								logging.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								logging.go
									
									
									
									
									
								
							@@ -1,12 +1,16 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"github.com/rs/zerolog"
 | 
						"github.com/rs/zerolog"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fatal hook to run in case of Fatal error
 | 
				
			||||||
type FatalHook struct {}
 | 
					type FatalHook struct {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Run function on trigger
 | 
				
			||||||
func (hook FatalHook) Run(_ *zerolog.Event, level zerolog.Level, _ string) {
 | 
					func (hook FatalHook) Run(_ *zerolog.Event, level zerolog.Level, _ string) {
 | 
				
			||||||
	// If log event is fatal
 | 
						// If log event is fatal
 | 
				
			||||||
	if level == zerolog.FatalLevel {
 | 
						if level == zerolog.FatalLevel {
 | 
				
			||||||
@@ -14,3 +18,22 @@ func (hook FatalHook) Run(_ *zerolog.Event, level zerolog.Level, _ string) {
 | 
				
			|||||||
		_ = os.RemoveAll(opensendDir)
 | 
							_ = os.RemoveAll(opensendDir)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TCP Fatal hook to run in case of Fatal error with open TCP connection
 | 
				
			||||||
 | 
					type TCPFatalHook struct {
 | 
				
			||||||
 | 
						conn net.Conn
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Run function on trigger
 | 
				
			||||||
 | 
					func (hook TCPFatalHook) Run(_ *zerolog.Event, level zerolog.Level, _ string) {
 | 
				
			||||||
 | 
						// If log event is fatal
 | 
				
			||||||
 | 
						if level == zerolog.FatalLevel {
 | 
				
			||||||
 | 
							// Send error to connection
 | 
				
			||||||
 | 
							_, _ = fmt.Fprintln(hook.conn, "ERR;")
 | 
				
			||||||
 | 
							// Close connection
 | 
				
			||||||
 | 
							_ = hook.conn.Close()
 | 
				
			||||||
 | 
							// Attempt removal of opensend directory
 | 
				
			||||||
 | 
							_ = os.RemoveAll(opensendDir)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								main.go
									
									
									
									
									
								
							@@ -112,6 +112,14 @@ func main() {
 | 
				
			|||||||
			// Get IP of chosen receiver
 | 
								// Get IP of chosen receiver
 | 
				
			||||||
			choiceIP = discoveredIPs[choiceIndex]
 | 
								choiceIP = discoveredIPs[choiceIndex]
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							// Instantiate Config object
 | 
				
			||||||
 | 
							config := NewConfig(*actionType, *actionData)
 | 
				
			||||||
 | 
							// Validate data in config struct
 | 
				
			||||||
 | 
							config.Validate()
 | 
				
			||||||
 | 
							// Collect any files that may be required for transaction into opensend directory
 | 
				
			||||||
 | 
							config.CollectFiles(opensendDir)
 | 
				
			||||||
 | 
							// Create config file in opensend directory
 | 
				
			||||||
 | 
							config.CreateFile(opensendDir)
 | 
				
			||||||
		// Notify user of key exchange
 | 
							// Notify user of key exchange
 | 
				
			||||||
		log.Info().Msg("Performing key exchange")
 | 
							log.Info().Msg("Performing key exchange")
 | 
				
			||||||
		// Exchange RSA keys with receiver
 | 
							// Exchange RSA keys with receiver
 | 
				
			||||||
@@ -122,12 +130,6 @@ func main() {
 | 
				
			|||||||
		key := EncryptKey(sharedKey, rawKey)
 | 
							key := EncryptKey(sharedKey, rawKey)
 | 
				
			||||||
		// Save encrypted key in opensend directory as key.aes
 | 
							// Save encrypted key in opensend directory as key.aes
 | 
				
			||||||
		SaveEncryptedKey(key, opensendDir + "/key.aes")
 | 
							SaveEncryptedKey(key, opensendDir + "/key.aes")
 | 
				
			||||||
		// Instantiate Config object
 | 
					 | 
				
			||||||
		config := NewConfig(*actionType, *actionData)
 | 
					 | 
				
			||||||
		// Collect any files that may be required for transaction into opensend directory
 | 
					 | 
				
			||||||
		config.CollectFiles(opensendDir)
 | 
					 | 
				
			||||||
		// Create config file in opensend directory
 | 
					 | 
				
			||||||
		config.CreateFile(opensendDir)
 | 
					 | 
				
			||||||
		// Notify user file encryption is beginning
 | 
							// Notify user file encryption is beginning
 | 
				
			||||||
		log.Info().Msg("Encrypting files")
 | 
							log.Info().Msg("Encrypting files")
 | 
				
			||||||
		// Encrypt all files in opensend directory using shared key
 | 
							// Encrypt all files in opensend directory using shared key
 | 
				
			||||||
@@ -157,12 +159,14 @@ func main() {
 | 
				
			|||||||
		time.Sleep(300*time.Millisecond)
 | 
							time.Sleep(300*time.Millisecond)
 | 
				
			||||||
		// Notify user files are being received
 | 
							// Notify user files are being received
 | 
				
			||||||
		log.Info().Msg("Receiving files from server (This may take a while)")
 | 
							log.Info().Msg("Receiving files from server (This may take a while)")
 | 
				
			||||||
 | 
							// Connect to sender's TCP socket
 | 
				
			||||||
 | 
							connection := ConnectToSender(senderIP)
 | 
				
			||||||
		// Get files from sender and place them into the opensend directory
 | 
							// Get files from sender and place them into the opensend directory
 | 
				
			||||||
		RecvFiles(senderIP)
 | 
							RecvFiles(connection)
 | 
				
			||||||
		// Get encrypted shared key from sender
 | 
							// Get encrypted shared key from sender
 | 
				
			||||||
		encryptedKey := GetKey(senderIP)
 | 
							encryptedKey := GetKey(connection)
 | 
				
			||||||
		// Send stop signal to sender's HTTP server
 | 
							// Send stop signal to sender's HTTP server
 | 
				
			||||||
		SendSrvStopSignal(senderIP)
 | 
							SendSrvStopSignal(connection)
 | 
				
			||||||
		// Decrypt shared key
 | 
							// Decrypt shared key
 | 
				
			||||||
		sharedKey := DecryptKey(encryptedKey, privateKey)
 | 
							sharedKey := DecryptKey(encryptedKey, privateKey)
 | 
				
			||||||
		// Notify user file decryption is beginning
 | 
							// Notify user file decryption is beginning
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user