Gofmt all files
Some checks failed
metroline Metroline pipeline status (https://metroline.io).

This commit is contained in:
Elara 2020-12-20 23:18:42 -08:00
parent c708c17177
commit 8a439c74de
8 changed files with 282 additions and 114 deletions

111
config.go
View File

@ -26,7 +26,7 @@ func NewConfig(actionType string, actionData string) *Config {
return &Config{ActionType: actionType, ActionData: actionData}
}
func (config *Config) Validate() {
func (config *Config) Validate() {
if config.ActionType == "url" {
// Parse URL in config
urlParser, err := url.Parse(config.ActionData)
@ -52,15 +52,21 @@ func (config *Config) CreateFile(dir string) {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Create config file at given directory
configFile, err := os.Create(dir + "/config.json")
if err != nil { log.Fatal().Err(err).Msg("Error creating config file") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating config file")
}
// Close config file at the end of this function
defer configFile.Close()
// Marshal given Config struct into a []byte
jsonData, err := json.Marshal(config)
if err != nil { log.Fatal().Err(err).Msg("Error encoding JSON") }
if err != nil {
log.Fatal().Err(err).Msg("Error encoding JSON")
}
// Write []byte to previously created config file
bytesWritten, err := configFile.Write(jsonData)
if err != nil { log.Fatal().Err(err).Msg("Error writing JSON to file") }
if err != nil {
log.Fatal().Err(err).Msg("Error writing JSON to file")
}
// Log bytes written
log.Info().Str("file", "config.json").Msg("Wrote " + strconv.Itoa(bytesWritten) + " bytes")
}
@ -73,23 +79,31 @@ func (config *Config) CollectFiles(dir string) {
if config.ActionType == "file" {
// Open file path in config.ActionData
src, err := os.Open(config.ActionData)
if err != nil { log.Fatal().Err(err).Msg("Error opening file from config") }
if err != nil {
log.Fatal().Err(err).Msg("Error opening file from config")
}
// Close source file at the end of this function
defer src.Close()
// Create new file with the same name at given directory
dst, err := os.Create(dir + "/" + filepath.Base(config.ActionData))
if err != nil { log.Fatal().Err(err).Msg("Error creating file") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating file")
}
// Close new file at the end of this function
defer dst.Close()
// Copy data from source file to destination file
_, err = io.Copy(dst, src)
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")
}
// Replace file path in config.ActionData with file name
config.ActionData = filepath.Base(config.ActionData)
} else if config.ActionType == "dir" {
// Create tar archive
tarFile, err := os.Create(dir + "/" + filepath.Base(config.ActionData) + ".tar")
if err != nil { log.Fatal().Err(err).Msg("Error creating file") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating file")
}
// Close tar file at the end of this function
defer tarFile.Close()
// Create writer for tar archive
@ -99,27 +113,41 @@ func (config *Config) CollectFiles(dir string) {
// Walk given directory
err = filepath.Walk(config.ActionData, func(path string, info os.FileInfo, err error) error {
// Return if error walking
if err != nil { return err }
if err != nil {
return err
}
// Skip if file is not normal mode
if !info.Mode().IsRegular() { return nil }
if !info.Mode().IsRegular() {
return nil
}
// Create tar header for file
header, err := tar.FileInfoHeader(info, info.Name())
if err != nil { return err }
if err != nil {
return err
}
// Change header name to reflect decompressed filepath
header.Name = strings.TrimPrefix(strings.ReplaceAll(path, config.ActionData, ""), string(filepath.Separator))
// Write header to archive
if err := tarArchiver.WriteHeader(header); err != nil { return err }
if err := tarArchiver.WriteHeader(header); err != nil {
return err
}
// Open source file
src, err := os.Open(path)
if err != nil { return err }
if err != nil {
return err
}
// Close source file at the end of this function
defer src.Close()
// Copy source bytes to tar archive
if _, err := io.Copy(tarArchiver, src); err != nil { return err }
if _, err := io.Copy(tarArchiver, src); err != nil {
return err
}
// Return at the end of the function
return nil
})
if err != nil { log.Fatal().Err(err).Msg("Error creating tar archive") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating tar archive")
}
// Set config data to base path for receiver
config.ActionData = filepath.Base(config.ActionData)
}
@ -131,10 +159,14 @@ func (config *Config) ReadFile(filePath string) {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Read file at filePath
fileData, err := ioutil.ReadFile(filePath)
if err != nil { log.Fatal().Err(err).Msg("Error reading config file") }
if err != nil {
log.Fatal().Err(err).Msg("Error reading config file")
}
// Unmarshal data from JSON into config struct
err = json.Unmarshal(fileData, config)
if err != nil { log.Fatal().Err(err).Msg("Error decoding JSON") }
if err != nil {
log.Fatal().Err(err).Msg("Error decoding JSON")
}
}
// Execute action specified in config
@ -145,18 +177,24 @@ func (config *Config) ExecuteAction(srcDir string, destDir string) {
if config.ActionType == "file" {
// Open file from config at given directory
src, err := os.Open(srcDir + "/" + config.ActionData)
if err != nil { log.Fatal().Err(err).Msg("Error reading file from config") }
if err != nil {
log.Fatal().Err(err).Msg("Error reading file from config")
}
// Close source file at the end of this function
defer src.Close()
// Create file in user's Downloads directory
dst, err := os.Create(filepath.Clean(destDir) + "/" + config.ActionData)
if err != nil { log.Fatal().Err(err).Msg("Error creating file") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating file")
}
// Close destination file at the end of this function
defer dst.Close()
// Copy data from source file to destination file
_, err = io.Copy(dst, src)
if err != nil { log.Fatal().Err(err).Msg("Error copying data to file") }
// If action is url
if err != nil {
log.Fatal().Err(err).Msg("Error copying data to file")
}
// If action is url
} else if config.ActionType == "url" {
// Parse received URL
urlParser, err := url.Parse(config.ActionData)
@ -164,34 +202,41 @@ func (config *Config) ExecuteAction(srcDir string, destDir string) {
if err != nil {
// Alert user of invalid url
log.Fatal().Err(err).Msg("Invalid URL")
// If scheme is not detected
// 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
// 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
err = browser.OpenURL(config.ActionData)
if err != nil { log.Fatal().Err(err).Msg("Error opening browser") }
// If action is dir
if err != nil {
log.Fatal().Err(err).Msg("Error opening browser")
}
// If action is dir
} else if config.ActionType == "dir" {
// Set destination directory to ~/Downloads/{dir name}
dstDir := filepath.Clean(destDir) + "/" + config.ActionData
// Try to create destination directory
err := os.MkdirAll(dstDir, 0755)
if err != nil { log.Fatal().Err(err).Msg("Error creating directory") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating directory")
}
// Try to open tar archive file
tarFile, err := os.Open(srcDir + "/" + config.ActionData + ".tar")
if err != nil { log.Fatal().Err(err).Msg("Error opening tar archive") }
if err != nil {
log.Fatal().Err(err).Msg("Error opening tar archive")
}
// Close tar archive file at the end of this function
defer tarFile.Close()
// Create tar reader to unarchive tar archive
tarUnarchiver := tar.NewReader(tarFile)
// Loop to recursively unarchive tar file
unarchiveLoop: for {
unarchiveLoop:
for {
// Jump to next header in tar archive
header, err := tarUnarchiver.Next()
switch {
@ -215,13 +260,17 @@ func (config *Config) ExecuteAction(srcDir string, destDir string) {
_ = os.MkdirAll(filepath.Dir(targetPath), 0755)
// Create file with mode contained in header at target path
dstFile, err := os.OpenFile(targetPath, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
if err != nil { log.Fatal().Err(err).Msg("Error creating file during unarchiving") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating file during unarchiving")
}
// Copy data from tar archive into file
_, err = io.Copy(dstFile, tarUnarchiver)
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")
}
}
}
// Catchall
// Catchall
} else {
// Log unknown action type
log.Fatal().Msg("Unknown action type " + config.ActionType)

View File

@ -15,7 +15,9 @@ func DiscoverReceivers() ([]string, []string) {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Create zeroconf resolver
resolver, err := zeroconf.NewResolver(nil)
if err != nil { log.Fatal().Err(err).Msg("Error creating zeroconf resolver") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating zeroconf resolver")
}
// Create channel for zeroconf entries
entries := make(chan *zeroconf.ServiceEntry)
// Create slice to store hostnames of discovered receivers
@ -39,7 +41,9 @@ func DiscoverReceivers() ([]string, []string) {
defer cancel()
// Browse for mDNS entries
err = resolver.Browse(ctx, "_opensend._tcp", "local.", entries)
if err != nil { log.Fatal().Err(err).Msg("Error browsing zeroconf services") }
if err != nil {
log.Fatal().Err(err).Msg("Error browsing zeroconf services")
}
// Send Done signal to context
<-ctx.Done()
@ -53,7 +57,9 @@ func RegisterService() func() {
hostname, _ := os.Hostname()
// Register zeroconf service {hostname}._opensend._tcp.local.
server, err := zeroconf.Register(hostname, "_opensend._tcp", "local.", 9797, []string{"txtv=0", "lo=1", "la=2"}, nil)
if err != nil { log.Fatal().Err(err).Msg("Error registering zeroconf service") }
if err != nil {
log.Fatal().Err(err).Msg("Error registering zeroconf service")
}
// Return server.Shutdown() function to allow for shutdown in main()
return server.Shutdown
}

View File

@ -24,20 +24,28 @@ func CompressAndEncryptFile(filePath string, newFilePath string, sharedKey strin
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Read data from file
file, err := os.Open(filePath)
if err != nil { log.Fatal().Err(err).Msg("Error opening file") }
if err != nil {
log.Fatal().Err(err).Msg("Error opening file")
}
// Create buffer for compressed data
compressedBuffer := new(bytes.Buffer)
// Create Zstd encoder
zstdEncoder, err := zstd.NewWriter(compressedBuffer)
if err != nil { log.Fatal().Err(err).Msg("Error creating Zstd encoder") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating Zstd encoder")
}
// Copy file data to Zstd encoder
_, err = io.Copy(zstdEncoder, file)
if err != nil { log.Fatal().Err(err).Msg("Error reading file") }
if err != nil {
log.Fatal().Err(err).Msg("Error reading file")
}
// Close Zstd encoder
zstdEncoder.Close()
// Read compressed data into data variable
data, err := ioutil.ReadAll(compressedBuffer)
if err != nil { log.Fatal().Err(err).Msg("Error reading compressed buffer") }
if err != nil {
log.Fatal().Err(err).Msg("Error reading compressed buffer")
}
// Create md5 hash of password in order to make it the required size
md5Hash := md5.New()
md5Hash.Write([]byte(sharedKey))
@ -45,25 +53,35 @@ func CompressAndEncryptFile(filePath string, newFilePath string, sharedKey strin
hashedKey := hex.EncodeToString(md5Hash.Sum(nil))
// Create new AES cipher
block, err := aes.NewCipher([]byte(hashedKey))
if err != nil { log.Fatal().Err(err).Msg("Error creating AES cipher") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating AES cipher")
}
// Create GCM for AES cipher
gcm, err := cipher.NewGCM(block)
if err != nil { log.Fatal().Err(err).Msg("Error creating GCM") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating GCM")
}
// Make byte slice for nonce
nonce := make([]byte, gcm.NonceSize())
// Read random bytes into nonce slice
_, err = io.ReadFull(rand.Reader, nonce)
if err != nil { log.Fatal().Err(err).Msg("Error creating nonce") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating nonce")
}
// Encrypt data
ciphertext := gcm.Seal(nonce, nonce, data, nil)
// Create new file
newFile, err := os.Create(newFilePath)
if err != nil { log.Fatal().Err(err).Msg("Error creating file") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating file")
}
// Defer file close
defer newFile.Close()
// Write ciphertext to new file
bytesWritten, err := newFile.Write(ciphertext)
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 and to which file
log.Info().Str("file", filepath.Base(newFilePath)).Msg("Wrote " + strconv.Itoa(bytesWritten) + " bytes")
}
@ -74,7 +92,9 @@ func DecryptAndDecompressFile(filePath string, newFilePath string, sharedKey str
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Read data from file
data, err := ioutil.ReadFile(filePath)
if err != nil { log.Fatal().Err(err).Msg("Error reading file") }
if err != nil {
log.Fatal().Err(err).Msg("Error reading file")
}
// Create md5 hash of password in order to make it the required size
md5Hash := md5.New()
md5Hash.Write([]byte(sharedKey))
@ -83,25 +103,35 @@ func DecryptAndDecompressFile(filePath string, newFilePath string, sharedKey str
block, _ := aes.NewCipher([]byte(hashedKey))
// Create GCM for AES cipher
gcm, err := cipher.NewGCM(block)
if err != nil { log.Fatal().Err(err).Msg("Error creating GCM") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating GCM")
}
// Get standard GCM nonce size
nonceSize := gcm.NonceSize()
// Get nonce and ciphertext from data
nonce, ciphertext := data[:nonceSize], data[nonceSize:]
// Decrypt data
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil { log.Fatal().Err(err).Msg("Error decrypting data") }
if err != nil {
log.Fatal().Err(err).Msg("Error decrypting data")
}
// Create new Zstd decoder
zstdDecoder, err := zstd.NewReader(bytes.NewBuffer(plaintext))
if err != nil { log.Fatal().Err(err).Msg("Error creating Zstd decoder") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating Zstd decoder")
}
// Create new file
newFile, err := os.Create(newFilePath)
if err != nil { log.Fatal().Err(err).Msg("Error creating file") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating file")
}
// Close new file at the end of this function
defer newFile.Close()
// Write decompressed plaintext to new file
bytesWritten, err := io.Copy(newFile, zstdDecoder)
if err != nil { log.Fatal().Err(err).Msg("Error writing to file") }
if err != nil {
log.Fatal().Err(err).Msg("Error writing to file")
}
zstdDecoder.Close()
// Log bytes written and to which file
log.Info().Str("file", filepath.Base(newFilePath)).Msg("Wrote " + strconv.Itoa(int(bytesWritten)) + " bytes")
@ -114,19 +144,25 @@ func EncryptFiles(dir string, sharedKey string) {
// Walk given directory
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
// If error reading, return err
if err != nil { return err }
if err != nil {
return err
}
// If file is not a directory and is not the key
if !info.IsDir() && !strings.Contains(path, "key.aes"){
if !info.IsDir() && !strings.Contains(path, "key.aes") {
// Compress and Encrypt the file using shared key, appending .zst.enc
CompressAndEncryptFile(path, path + ".zst.enc", sharedKey)
CompressAndEncryptFile(path, path+".zst.enc", sharedKey)
// Remove unencrypted file
err := os.Remove(path)
if err != nil { return err }
if err != nil {
return err
}
}
// Return nil if no error occurs
return nil
})
if err != nil { log.Fatal().Err(err).Msg("Error encrypting files") }
if err != nil {
log.Fatal().Err(err).Msg("Error encrypting files")
}
}
// Decrypt files in given directory using shared key
@ -136,7 +172,9 @@ func DecryptFiles(dir string, sharedKey string) {
// Walk given directory
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
// If error reading, return err
if err != nil { return err }
if err != nil {
return err
}
// If file is not a directory and is encrypted
if !info.IsDir() && strings.Contains(path, ".enc") {
// Decrypt and decompress the file using the shared key, removing .zst.enc
@ -145,5 +183,7 @@ func DecryptFiles(dir string, sharedKey string) {
// Return nil if no errors occurred
return nil
})
if err != nil { log.Fatal().Err(err).Msg("Error decrypting files") }
if err != nil {
log.Fatal().Err(err).Msg("Error decrypting files")
}
}

View File

@ -23,12 +23,16 @@ func SaveEncryptedKey(encryptedKey []byte, filePath string) {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Create file at given file path
keyFile, err := os.Create(filePath)
if err != nil { log.Fatal().Err(err).Msg("Error creating file") }
if err != nil {
log.Fatal().Err(err).Msg("Error creating file")
}
// Close file at the end of this function
defer keyFile.Close()
// Write encrypted key to file
bytesWritten, err := keyFile.Write(encryptedKey)
if err != nil { log.Fatal().Err(err).Msg("Error writing key to file") }
if err != nil {
log.Fatal().Err(err).Msg("Error writing key to file")
}
// Log bytes written
log.Info().Str("file", filepath.Base(filePath)).Msg("Wrote " + strconv.Itoa(bytesWritten) + " bytes")
}
@ -39,42 +43,59 @@ func SendFiles(dir string) {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Create TCP listener on port 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
connection, err := listener.Accept()
if err != nil { log.Fatal().Err(err).Msg("Error accepting connection") }
if err != nil {
log.Fatal().Err(err).Msg("Error accepting connection")
}
// Close connection at the end of this function
defer connection.Close()
// Create for loop to listen for messages on connection
connectionLoop: for {
connectionLoop:
for {
// Use ConsoleWriter logger with TCPFatalHook
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(TCPFatalHook{conn: connection})
// Attempt to read new message on connection
data, err := bufio.NewReader(connection).ReadString('\n')
// If no message detected, try again
if err != nil && err.Error() == "EOF" { continue }
if err != nil && err.Error() == "EOF" {
continue
}
// If non-EOF error, fatally log
if err != nil { log.Fatal().Err(err).Msg("Error reading data") }
if err != nil {
log.Fatal().Err(err).Msg("Error reading data")
}
// Process received data
processedData := strings.Split(strings.TrimSpace(data), ";")
// If processedData is empty, alert the user of invalid data
if len(processedData) < 1 { log.Fatal().Str("data", data).Msg("Received data invalid") }
if len(processedData) < 1 {
log.Fatal().Str("data", data).Msg("Received data invalid")
}
switch processedData[0] {
case "key":
// Inform user client has requested key
log.Info().Msg("Key requested")
// Read saved key
key, err := ioutil.ReadFile(dir + "/key.aes")
if err != nil { log.Fatal().Err(err).Msg("Error reading key") }
if err != nil {
log.Fatal().Err(err).Msg("Error reading key")
}
// Write saved key to ResponseWriter
_, err = fmt.Fprintln(connection, "OK;" + hex.EncodeToString(key) + ";")
if err != nil { log.Fatal().Err(err).Msg("Error writing response") }
_, err = fmt.Fprintln(connection, "OK;"+hex.EncodeToString(key)+";")
if err != nil {
log.Fatal().Err(err).Msg("Error writing response")
}
case "index":
// Inform user a client has requested the file index
log.Info().Msg("Index requested")
// Get directory listing
dirListing, err := ioutil.ReadDir(dir)
if err != nil { log.Fatal().Err(err).Msg("Error reading directory") }
if err != nil {
log.Fatal().Err(err).Msg("Error reading directory")
}
// Create new slice to house filenames for index
var indexSlice []string
// For each file in listing
@ -88,8 +109,10 @@ func SendFiles(dir string) {
// 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") }
_, 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 {
@ -114,8 +137,10 @@ func SendFiles(dir string) {
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") }
_, 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")
@ -162,40 +187,56 @@ func RecvFiles(connection net.Conn) {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Request index from sender
_, err := fmt.Fprintln(connection, "index;")
if err != nil { log.Fatal().Err(err).Msg("Error sending index request") }
if err != nil {
log.Fatal().Err(err).Msg("Error sending index request")
}
// Read received message
message, err := bufio.NewReader(connection).ReadString('\n')
if err != nil { log.Fatal().Err(err).Msg("Error getting index") }
if err != nil {
log.Fatal().Err(err).Msg("Error getting index")
}
// Process received message
procMessage := strings.Split(strings.TrimSpace(message), ";")
// If non-ok code returned, fatally log
if procMessage[0] != "OK" { log.Fatal().Err(err).Msg("Sender reported error") }
if procMessage[0] != "OK" {
log.Fatal().Err(err).Msg("Sender reported error")
}
// Get index from message
index := strings.Split(strings.TrimSpace(procMessage[1]), "|")
for _, file := range index {
// Get current file in index
_, err = fmt.Fprintln(connection, "file;" + file + ";")
if err != nil { log.Fatal().Err(err).Msg("Error sending file request") }
_, 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")
}
// Process received message
procMessage := strings.Split(message, ";")
// If non-ok code returned
if procMessage[0] != "OK" {
// fatally log
log.Fatal().Err(err).Msg("Sender reported error")
// Otherwise
// Otherwise
} else {
// Create new file at index filepath
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") }
if err != nil {
log.Fatal().Err(err).Msg("Error decoding hex")
}
// Copy response body to new file
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.Info().Str("file", filepath.Base(file)).Msg("Wrote " + strconv.Itoa(int(bytesWritten)) + " bytes")
// Close new file

View File

@ -20,7 +20,9 @@ func GenerateRSAKeypair() (*rsa.PrivateKey, *rsa.PublicKey) {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Generate private/public RSA keypair
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil { log.Fatal().Err(err).Msg("Error generating RSA keypair") }
if err != nil {
log.Fatal().Err(err).Msg("Error generating RSA keypair")
}
// Get public key
publicKey := privateKey.PublicKey
// Return keypair
@ -33,23 +35,31 @@ func GetKey(connection net.Conn) []byte {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Send key request to connection
_, err := fmt.Fprintln(connection, "key;")
if err != nil { log.Fatal().Err(err).Msg("Error sending key request") }
if err != nil {
log.Fatal().Err(err).Msg("Error sending key request")
}
// 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")
}
// Process received message
procMessage := strings.Split(strings.TrimSpace(message), ";")
// If ok code returned
if procMessage[0] == "OK" {
// Decode received hex string into key
key, err := hex.DecodeString(procMessage[1])
if err != nil { log.Fatal().Err(err).Msg("Error reading key") }
if err != nil {
log.Fatal().Err(err).Msg("Error reading key")
}
// Return key
return key
// Otherwise
// Otherwise
} else {
// Fatally log
if err != nil { log.Fatal().Msg("Server reported error") }
if err != nil {
log.Fatal().Msg("Server reported error")
}
}
// Return nil if all else fails
return nil
@ -61,7 +71,9 @@ func EncryptKey(sharedKey string, recvPubKey *rsa.PublicKey) []byte {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Encrypt shared key using RSA
encryptedSharedKey, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, recvPubKey, []byte(sharedKey), nil)
if err != nil { log.Fatal().Err(err).Msg("Error encrypting shared key") }
if err != nil {
log.Fatal().Err(err).Msg("Error encrypting shared key")
}
// Return encrypted key
return encryptedSharedKey
}
@ -70,7 +82,9 @@ func EncryptKey(sharedKey string, recvPubKey *rsa.PublicKey) []byte {
func DecryptKey(encryptedKey []byte, privateKey *rsa.PrivateKey) string {
// Decrypt shared key using RSA
decryptedKey, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, encryptedKey, nil)
if err != nil { log.Fatal().Err(err).Msg("Error decrypting shared key") }
if err != nil {
log.Fatal().Err(err).Msg("Error decrypting shared key")
}
// Get string of decrypted key
sharedKey := string(decryptedKey)
// Return shared key

View File

@ -15,20 +15,26 @@ func ReceiverKeyExchange(key *rsa.PublicKey) string {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Create TCP listener on port 9797
listener, err := net.Listen("tcp", ":9797")
if err != nil { log.Fatal().Err(err).Msg("Error starting listener") }
if err != nil {
log.Fatal().Err(err).Msg("Error starting listener")
}
// Create string for sender address
var senderAddr string
for {
// Accept connection on listener
connection, err := listener.Accept()
if err != nil { log.Fatal().Err(err).Msg("Error accepting connections") }
if err != nil {
log.Fatal().Err(err).Msg("Error accepting connections")
}
// Get sender address and store it in senderAddr
senderAddr = connection.RemoteAddr().String()
// Create gob encoder with connection as io.Writer
encoder := gob.NewEncoder(connection)
// Encode key into connection
err = encoder.Encode(key)
if err != nil { log.Fatal().Err(err).Msg("Error encoding key") }
if err != nil {
log.Fatal().Err(err).Msg("Error encoding key")
}
return senderAddr
}
}
@ -38,15 +44,19 @@ func SenderKeyExchange(receiverIP string) *rsa.PublicKey {
// Use ConsoleWriter logger
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
// Connect to TCP socket on receiver IP port 9797
connection, err := net.Dial("tcp", receiverIP + ":9797")
if err != nil { log.Fatal().Err(err).Msg("Error connecting to sender") }
connection, err := net.Dial("tcp", receiverIP+":9797")
if err != nil {
log.Fatal().Err(err).Msg("Error connecting to sender")
}
// Create gob decoder
decoder := gob.NewDecoder(connection)
// Instantiate rsa.PublicKey struct
recvPubKey := &rsa.PublicKey{}
// Decode key
err = decoder.Decode(recvPubKey)
if err != nil { log.Fatal().Err(err).Msg("Error decoding key") }
if err != nil {
log.Fatal().Err(err).Msg("Error decoding key")
}
// Return received key
return recvPubKey
}

View File

@ -8,7 +8,7 @@ import (
)
// 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) {

28
main.go
View File

@ -25,7 +25,9 @@ func main() {
// Get user's home directory
homeDir, err := os.UserHomeDir()
if err != nil { log.Fatal().Err(err).Msg("Error getting home directory") }
if err != nil {
log.Fatal().Err(err).Msg("Error getting home directory")
}
// Define opensend directory as ~/.opensend
opensendDir = homeDir + "/.opensend"
@ -50,11 +52,11 @@ func main() {
// Create --send-to flag to send to a specific IP
sendTo := flag.String("send-to", "", "Use IP address of receiver instead of mDNS")
// Create --dest-dir flag to save to a specified folder
destDir := flag.String("dest-dir", homeDir + "/Downloads", "Destination directory for files or dirs sent over opensend")
destDir := flag.String("dest-dir", homeDir+"/Downloads", "Destination directory for files or dirs sent over opensend")
// Create --skip-mdns to skip service registration
skipMdns := flag.Bool("skip-mdns", false, "Skip zeroconf service registration (use if mdns fails)")
// Create -t flag for type
actionType := flag.String("t", "","Type of data being sent")
actionType := flag.String("t", "", "Type of data being sent")
// Create -d flag for data
actionData := flag.String("d", "", "Data to send")
// Create -s flag for sending
@ -75,7 +77,9 @@ func main() {
sharedKeyBytes := make([]byte, 32)
// Read random bytes into buffer
_, err := io.ReadFull(rand.Reader, sharedKeyBytes)
if err != nil { log.Fatal().Err(err).Msg("Error generating random bytes") }
if err != nil {
log.Fatal().Err(err).Msg("Error generating random bytes")
}
// Encode random bytes to hexadecimal
sharedKey := hex.EncodeToString(sharedKeyBytes)
// Notify user a key has been created
@ -88,7 +92,7 @@ func main() {
log.Info().Msg("IP provided. Skipping discovery.")
// Set chosen IP to provided
choiceIP = *sendTo
// Otherwise
// Otherwise
} else {
// Notify user device discovery is beginning
log.Info().Msg("Discovering opensend receivers")
@ -106,7 +110,9 @@ func main() {
choiceStr, _ := reader.ReadString('\n')
// Convert input to int after trimming spaces
choiceInt, err := strconv.Atoi(strings.TrimSpace(choiceStr))
if err != nil { log.Fatal().Err(err).Msg("Error converting choice to int") }
if err != nil {
log.Fatal().Err(err).Msg("Error converting choice to int")
}
// Set choiceIndex to choiceInt-1 to allow for indexing
choiceIndex := choiceInt - 1
// Get IP of chosen receiver
@ -129,7 +135,7 @@ func main() {
// Encrypt shared key using RSA public key
key := EncryptKey(sharedKey, rawKey)
// Save encrypted key in opensend directory as key.aes
SaveEncryptedKey(key, opensendDir + "/key.aes")
SaveEncryptedKey(key, opensendDir+"/key.aes")
// Notify user file encryption is beginning
log.Info().Msg("Encrypting files")
// Encrypt all files in opensend directory using shared key
@ -138,7 +144,7 @@ func main() {
log.Info().Msg("Server started on port 9898")
// Send all files in opensend directory using an HTTP server on port 9898
SendFiles(opensendDir)
// If -r given
// If -r given
} else if *recvFlag {
// If --skip-mdns is not given
if !*skipMdns {
@ -156,7 +162,7 @@ func main() {
// Exchange keys with sender
senderIP := ReceiverKeyExchange(publicKey)
// Sleep 300ms to allow sender time to start HTTP server
time.Sleep(300*time.Millisecond)
time.Sleep(300 * time.Millisecond)
// Notify user files are being received
log.Info().Msg("Receiving files from server (This may take a while)")
// Connect to sender's TCP socket
@ -187,5 +193,7 @@ func main() {
}
// Remove opensend directory
err = os.RemoveAll(opensendDir)
if err != nil { log.Fatal().Err(err).Msg("Error removing opensend directory") }
if err != nil {
log.Fatal().Err(err).Msg("Error removing opensend directory")
}
}