This commit is contained in:
parent
c708c17177
commit
8a439c74de
113
config.go
113
config.go
@ -26,7 +26,7 @@ func NewConfig(actionType string, actionData string) *Config {
|
|||||||
return &Config{ActionType: actionType, ActionData: actionData}
|
return &Config{ActionType: actionType, ActionData: actionData}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *Config) Validate() {
|
func (config *Config) Validate() {
|
||||||
if config.ActionType == "url" {
|
if config.ActionType == "url" {
|
||||||
// Parse URL in config
|
// Parse URL in config
|
||||||
urlParser, err := url.Parse(config.ActionData)
|
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{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Create config file at given directory
|
// Create config file at given directory
|
||||||
configFile, err := os.Create(dir + "/config.json")
|
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
|
// Close config file at the end of this function
|
||||||
defer configFile.Close()
|
defer configFile.Close()
|
||||||
// Marshal given Config struct into a []byte
|
// Marshal given Config struct into a []byte
|
||||||
jsonData, err := json.Marshal(config)
|
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
|
// Write []byte to previously created config file
|
||||||
bytesWritten, err := configFile.Write(jsonData)
|
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 bytes written
|
||||||
log.Info().Str("file", "config.json").Msg("Wrote " + strconv.Itoa(bytesWritten) + " bytes")
|
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" {
|
if config.ActionType == "file" {
|
||||||
// Open file path in config.ActionData
|
// Open file path in config.ActionData
|
||||||
src, err := os.Open(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
|
// Close source file at the end of this function
|
||||||
defer src.Close()
|
defer src.Close()
|
||||||
// Create new file with the same name at given directory
|
// Create new file with the same name at given directory
|
||||||
dst, err := os.Create(dir + "/" + filepath.Base(config.ActionData))
|
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
|
// Close new file at the end of this function
|
||||||
defer dst.Close()
|
defer dst.Close()
|
||||||
// Copy data from source file to destination file
|
// Copy data from source file to destination file
|
||||||
_, err = io.Copy(dst, src)
|
_, 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
|
// Replace file path in config.ActionData with file name
|
||||||
config.ActionData = filepath.Base(config.ActionData)
|
config.ActionData = filepath.Base(config.ActionData)
|
||||||
} else if config.ActionType == "dir" {
|
} else if config.ActionType == "dir" {
|
||||||
// Create tar archive
|
// Create tar archive
|
||||||
tarFile, err := os.Create(dir + "/" + filepath.Base(config.ActionData) + ".tar")
|
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
|
// Close tar file at the end of this function
|
||||||
defer tarFile.Close()
|
defer tarFile.Close()
|
||||||
// Create writer for tar archive
|
// Create writer for tar archive
|
||||||
@ -99,27 +113,41 @@ func (config *Config) CollectFiles(dir string) {
|
|||||||
// Walk given directory
|
// Walk given directory
|
||||||
err = filepath.Walk(config.ActionData, func(path string, info os.FileInfo, err error) error {
|
err = filepath.Walk(config.ActionData, func(path string, info os.FileInfo, err error) error {
|
||||||
// Return if error walking
|
// Return if error walking
|
||||||
if err != nil { return err }
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Skip if file is not normal mode
|
// Skip if file is not normal mode
|
||||||
if !info.Mode().IsRegular() { return nil }
|
if !info.Mode().IsRegular() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
// Create tar header for file
|
// Create tar header for file
|
||||||
header, err := tar.FileInfoHeader(info, info.Name())
|
header, err := tar.FileInfoHeader(info, info.Name())
|
||||||
if err != nil { return err }
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Change header name to reflect decompressed filepath
|
// Change header name to reflect decompressed filepath
|
||||||
header.Name = strings.TrimPrefix(strings.ReplaceAll(path, config.ActionData, ""), string(filepath.Separator))
|
header.Name = strings.TrimPrefix(strings.ReplaceAll(path, config.ActionData, ""), string(filepath.Separator))
|
||||||
// Write header to archive
|
// 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
|
// Open source file
|
||||||
src, err := os.Open(path)
|
src, err := os.Open(path)
|
||||||
if err != nil { return err }
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Close source file at the end of this function
|
// Close source file at the end of this function
|
||||||
defer src.Close()
|
defer src.Close()
|
||||||
// Copy source bytes to tar archive
|
// 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 at the end of the function
|
||||||
return nil
|
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
|
// Set config data to base path for receiver
|
||||||
config.ActionData = filepath.Base(config.ActionData)
|
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{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Read file at filePath
|
// Read file at filePath
|
||||||
fileData, err := ioutil.ReadFile(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
|
// Unmarshal data from JSON into config struct
|
||||||
err = json.Unmarshal(fileData, config)
|
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
|
// Execute action specified in config
|
||||||
@ -145,18 +177,24 @@ func (config *Config) ExecuteAction(srcDir string, destDir string) {
|
|||||||
if config.ActionType == "file" {
|
if config.ActionType == "file" {
|
||||||
// Open file from config at given directory
|
// Open file from config at given directory
|
||||||
src, err := os.Open(srcDir + "/" + config.ActionData)
|
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
|
// Close source file at the end of this function
|
||||||
defer src.Close()
|
defer src.Close()
|
||||||
// Create file in user's Downloads directory
|
// Create file in user's Downloads directory
|
||||||
dst, err := os.Create(filepath.Clean(destDir) + "/" + config.ActionData)
|
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
|
// Close destination file at the end of this function
|
||||||
defer dst.Close()
|
defer dst.Close()
|
||||||
// Copy data from source file to destination file
|
// Copy data from source file to destination file
|
||||||
_, err = io.Copy(dst, src)
|
_, err = io.Copy(dst, src)
|
||||||
if err != nil { log.Fatal().Err(err).Msg("Error copying data to file") }
|
if err != nil {
|
||||||
// If action is url
|
log.Fatal().Err(err).Msg("Error copying data to file")
|
||||||
|
}
|
||||||
|
// If action is url
|
||||||
} else if config.ActionType == "url" {
|
} else if config.ActionType == "url" {
|
||||||
// Parse received URL
|
// Parse received URL
|
||||||
urlParser, err := url.Parse(config.ActionData)
|
urlParser, err := url.Parse(config.ActionData)
|
||||||
@ -164,34 +202,41 @@ func (config *Config) ExecuteAction(srcDir string, destDir string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// Alert user of invalid url
|
// Alert user of invalid url
|
||||||
log.Fatal().Err(err).Msg("Invalid URL")
|
log.Fatal().Err(err).Msg("Invalid URL")
|
||||||
// If scheme is not detected
|
// If scheme is not detected
|
||||||
} else if urlParser.Scheme == "" {
|
} else if urlParser.Scheme == "" {
|
||||||
// Alert user of invalid scheme
|
// Alert user of invalid scheme
|
||||||
log.Fatal().Msg("Invalid URL scheme")
|
log.Fatal().Msg("Invalid URL scheme")
|
||||||
// If host is not detected
|
// If host is not detected
|
||||||
} else if urlParser.Host == "" {
|
} else if urlParser.Host == "" {
|
||||||
// Alert user of invalid host
|
// Alert user of invalid host
|
||||||
log.Fatal().Msg("Invalid URL 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 {
|
||||||
// If action is dir
|
log.Fatal().Err(err).Msg("Error opening browser")
|
||||||
|
}
|
||||||
|
// If action is dir
|
||||||
} else if config.ActionType == "dir" {
|
} else if config.ActionType == "dir" {
|
||||||
// Set destination directory to ~/Downloads/{dir name}
|
// Set destination directory to ~/Downloads/{dir name}
|
||||||
dstDir := filepath.Clean(destDir) + "/" + config.ActionData
|
dstDir := filepath.Clean(destDir) + "/" + config.ActionData
|
||||||
// Try to create destination directory
|
// Try to create destination directory
|
||||||
err := os.MkdirAll(dstDir, 0755)
|
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
|
// Try to open tar archive file
|
||||||
tarFile, err := os.Open(srcDir + "/" + config.ActionData + ".tar")
|
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
|
// Close tar archive file at the end of this function
|
||||||
defer tarFile.Close()
|
defer tarFile.Close()
|
||||||
// Create tar reader to unarchive tar archive
|
// Create tar reader to unarchive tar archive
|
||||||
tarUnarchiver := tar.NewReader(tarFile)
|
tarUnarchiver := tar.NewReader(tarFile)
|
||||||
// Loop to recursively unarchive tar file
|
// Loop to recursively unarchive tar file
|
||||||
unarchiveLoop: for {
|
unarchiveLoop:
|
||||||
|
for {
|
||||||
// Jump to next header in tar archive
|
// Jump to next header in tar archive
|
||||||
header, err := tarUnarchiver.Next()
|
header, err := tarUnarchiver.Next()
|
||||||
switch {
|
switch {
|
||||||
@ -215,15 +260,19 @@ func (config *Config) ExecuteAction(srcDir string, destDir string) {
|
|||||||
_ = os.MkdirAll(filepath.Dir(targetPath), 0755)
|
_ = os.MkdirAll(filepath.Dir(targetPath), 0755)
|
||||||
// Create file with mode contained in header at target path
|
// 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))
|
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
|
// Copy data from tar archive into file
|
||||||
_, err = io.Copy(dstFile, tarUnarchiver)
|
_, 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 {
|
} else {
|
||||||
// Log unknown action type
|
// Log unknown action type
|
||||||
log.Fatal().Msg("Unknown action type " + config.ActionType)
|
log.Fatal().Msg("Unknown action type " + config.ActionType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,9 @@ func DiscoverReceivers() ([]string, []string) {
|
|||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Create zeroconf resolver
|
// Create zeroconf resolver
|
||||||
resolver, err := zeroconf.NewResolver(nil)
|
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
|
// Create channel for zeroconf entries
|
||||||
entries := make(chan *zeroconf.ServiceEntry)
|
entries := make(chan *zeroconf.ServiceEntry)
|
||||||
// Create slice to store hostnames of discovered receivers
|
// Create slice to store hostnames of discovered receivers
|
||||||
@ -39,7 +41,9 @@ func DiscoverReceivers() ([]string, []string) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
// Browse for mDNS entries
|
// Browse for mDNS entries
|
||||||
err = resolver.Browse(ctx, "_opensend._tcp", "local.", 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
|
// Send Done signal to context
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
@ -53,7 +57,9 @@ func RegisterService() func() {
|
|||||||
hostname, _ := os.Hostname()
|
hostname, _ := os.Hostname()
|
||||||
// Register zeroconf service {hostname}._opensend._tcp.local.
|
// Register zeroconf service {hostname}._opensend._tcp.local.
|
||||||
server, err := zeroconf.Register(hostname, "_opensend._tcp", "local.", 9797, []string{"txtv=0", "lo=1", "la=2"}, nil)
|
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() function to allow for shutdown in main()
|
||||||
return server.Shutdown
|
return server.Shutdown
|
||||||
}
|
}
|
||||||
|
@ -24,20 +24,28 @@ func CompressAndEncryptFile(filePath string, newFilePath string, sharedKey strin
|
|||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Read data from file
|
// Read data from file
|
||||||
file, err := os.Open(filePath)
|
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
|
// Create buffer for compressed data
|
||||||
compressedBuffer := new(bytes.Buffer)
|
compressedBuffer := new(bytes.Buffer)
|
||||||
// Create Zstd encoder
|
// Create Zstd encoder
|
||||||
zstdEncoder, err := zstd.NewWriter(compressedBuffer)
|
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
|
// Copy file data to Zstd encoder
|
||||||
_, err = io.Copy(zstdEncoder, file)
|
_, 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
|
// Close Zstd encoder
|
||||||
zstdEncoder.Close()
|
zstdEncoder.Close()
|
||||||
// Read compressed data into data variable
|
// Read compressed data into data variable
|
||||||
data, err := ioutil.ReadAll(compressedBuffer)
|
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
|
// Create md5 hash of password in order to make it the required size
|
||||||
md5Hash := md5.New()
|
md5Hash := md5.New()
|
||||||
md5Hash.Write([]byte(sharedKey))
|
md5Hash.Write([]byte(sharedKey))
|
||||||
@ -45,25 +53,35 @@ func CompressAndEncryptFile(filePath string, newFilePath string, sharedKey strin
|
|||||||
hashedKey := hex.EncodeToString(md5Hash.Sum(nil))
|
hashedKey := hex.EncodeToString(md5Hash.Sum(nil))
|
||||||
// Create new AES cipher
|
// Create new AES cipher
|
||||||
block, err := aes.NewCipher([]byte(hashedKey))
|
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
|
// Create GCM for AES cipher
|
||||||
gcm, err := cipher.NewGCM(block)
|
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
|
// Make byte slice for nonce
|
||||||
nonce := make([]byte, gcm.NonceSize())
|
nonce := make([]byte, gcm.NonceSize())
|
||||||
// Read random bytes into nonce slice
|
// Read random bytes into nonce slice
|
||||||
_, err = io.ReadFull(rand.Reader, nonce)
|
_, 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
|
// Encrypt data
|
||||||
ciphertext := gcm.Seal(nonce, nonce, data, nil)
|
ciphertext := gcm.Seal(nonce, nonce, data, nil)
|
||||||
// Create new file
|
// Create new file
|
||||||
newFile, err := os.Create(newFilePath)
|
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 file close
|
||||||
defer newFile.Close()
|
defer newFile.Close()
|
||||||
// Write ciphertext to new file
|
// Write ciphertext to new file
|
||||||
bytesWritten, err := newFile.Write(ciphertext)
|
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 bytes written and to which file
|
||||||
log.Info().Str("file", filepath.Base(newFilePath)).Msg("Wrote " + strconv.Itoa(bytesWritten) + " bytes")
|
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{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Read data from file
|
// Read data from file
|
||||||
data, err := ioutil.ReadFile(filePath)
|
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
|
// Create md5 hash of password in order to make it the required size
|
||||||
md5Hash := md5.New()
|
md5Hash := md5.New()
|
||||||
md5Hash.Write([]byte(sharedKey))
|
md5Hash.Write([]byte(sharedKey))
|
||||||
@ -83,25 +103,35 @@ func DecryptAndDecompressFile(filePath string, newFilePath string, sharedKey str
|
|||||||
block, _ := aes.NewCipher([]byte(hashedKey))
|
block, _ := aes.NewCipher([]byte(hashedKey))
|
||||||
// Create GCM for AES cipher
|
// Create GCM for AES cipher
|
||||||
gcm, err := cipher.NewGCM(block)
|
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
|
// Get standard GCM nonce size
|
||||||
nonceSize := gcm.NonceSize()
|
nonceSize := gcm.NonceSize()
|
||||||
// Get nonce and ciphertext from data
|
// Get nonce and ciphertext from data
|
||||||
nonce, ciphertext := data[:nonceSize], data[nonceSize:]
|
nonce, ciphertext := data[:nonceSize], data[nonceSize:]
|
||||||
// Decrypt data
|
// Decrypt data
|
||||||
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
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
|
// Create new Zstd decoder
|
||||||
zstdDecoder, err := zstd.NewReader(bytes.NewBuffer(plaintext))
|
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
|
// Create new file
|
||||||
newFile, err := os.Create(newFilePath)
|
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
|
// Close new file at the end of this function
|
||||||
defer newFile.Close()
|
defer newFile.Close()
|
||||||
// Write decompressed plaintext to new file
|
// Write decompressed plaintext to new file
|
||||||
bytesWritten, err := io.Copy(newFile, zstdDecoder)
|
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()
|
zstdDecoder.Close()
|
||||||
// Log bytes written and to which file
|
// Log bytes written and to which file
|
||||||
log.Info().Str("file", filepath.Base(newFilePath)).Msg("Wrote " + strconv.Itoa(int(bytesWritten)) + " bytes")
|
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
|
// Walk given directory
|
||||||
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||||
// If error reading, return err
|
// 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 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
|
// 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
|
// Remove unencrypted file
|
||||||
err := os.Remove(path)
|
err := os.Remove(path)
|
||||||
if err != nil { return err }
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Return nil if no error occurs
|
// Return nil if no error occurs
|
||||||
return nil
|
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
|
// Decrypt files in given directory using shared key
|
||||||
@ -136,7 +172,9 @@ func DecryptFiles(dir string, sharedKey string) {
|
|||||||
// Walk given directory
|
// Walk given directory
|
||||||
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||||
// If error reading, return err
|
// 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 file is not a directory and is encrypted
|
||||||
if !info.IsDir() && strings.Contains(path, ".enc") {
|
if !info.IsDir() && strings.Contains(path, ".enc") {
|
||||||
// Decrypt and decompress the file using the shared key, removing .zst.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 no errors occurred
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil { log.Fatal().Err(err).Msg("Error decrypting files") }
|
if err != nil {
|
||||||
}
|
log.Fatal().Err(err).Msg("Error decrypting files")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
95
files.go
95
files.go
@ -23,12 +23,16 @@ func SaveEncryptedKey(encryptedKey []byte, filePath string) {
|
|||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Create file at given file path
|
// Create file at given file path
|
||||||
keyFile, err := os.Create(filePath)
|
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
|
// Close file at the end of this function
|
||||||
defer keyFile.Close()
|
defer keyFile.Close()
|
||||||
// Write encrypted key to file
|
// Write encrypted key to file
|
||||||
bytesWritten, err := keyFile.Write(encryptedKey)
|
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 bytes written
|
||||||
log.Info().Str("file", filepath.Base(filePath)).Msg("Wrote " + strconv.Itoa(bytesWritten) + " bytes")
|
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{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Create TCP listener on port 9898
|
// Create TCP listener 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
|
// Accept connection on listener
|
||||||
connection, err := listener.Accept()
|
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
|
// Close connection at the end of this function
|
||||||
defer connection.Close()
|
defer connection.Close()
|
||||||
// Create for loop to listen for messages on connection
|
// Create for loop to listen for messages on connection
|
||||||
connectionLoop: for {
|
connectionLoop:
|
||||||
|
for {
|
||||||
// Use ConsoleWriter logger with TCPFatalHook
|
// Use ConsoleWriter logger with TCPFatalHook
|
||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(TCPFatalHook{conn: connection})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(TCPFatalHook{conn: connection})
|
||||||
// Attempt to read new message on connection
|
// Attempt to read new message on connection
|
||||||
data, err := bufio.NewReader(connection).ReadString('\n')
|
data, err := bufio.NewReader(connection).ReadString('\n')
|
||||||
// If no message detected, try again
|
// 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 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
|
// Process received data
|
||||||
processedData := strings.Split(strings.TrimSpace(data), ";")
|
processedData := strings.Split(strings.TrimSpace(data), ";")
|
||||||
// If processedData is empty, alert the user of invalid 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] {
|
switch processedData[0] {
|
||||||
case "key":
|
case "key":
|
||||||
// Inform user client has requested key
|
// Inform user client has requested key
|
||||||
log.Info().Msg("Key requested")
|
log.Info().Msg("Key requested")
|
||||||
// Read saved key
|
// Read saved key
|
||||||
key, err := ioutil.ReadFile(dir + "/key.aes")
|
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
|
// Write saved key to ResponseWriter
|
||||||
_, err = fmt.Fprintln(connection, "OK;" + hex.EncodeToString(key) + ";")
|
_, err = fmt.Fprintln(connection, "OK;"+hex.EncodeToString(key)+";")
|
||||||
if err != nil { log.Fatal().Err(err).Msg("Error writing response") }
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Error writing response")
|
||||||
|
}
|
||||||
case "index":
|
case "index":
|
||||||
// Inform user a client has requested the file index
|
// Inform user a client has requested the file index
|
||||||
log.Info().Msg("Index requested")
|
log.Info().Msg("Index requested")
|
||||||
// Get directory listing
|
// Get directory listing
|
||||||
dirListing, err := ioutil.ReadDir(dir)
|
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
|
// Create new slice to house filenames for index
|
||||||
var indexSlice []string
|
var indexSlice []string
|
||||||
// For each file in listing
|
// For each file in listing
|
||||||
@ -88,8 +109,10 @@ func SendFiles(dir string) {
|
|||||||
// Join index slice into string
|
// Join index slice into string
|
||||||
indexStr := strings.Join(indexSlice, "|")
|
indexStr := strings.Join(indexSlice, "|")
|
||||||
// Write index to ResponseWriter
|
// Write index to ResponseWriter
|
||||||
_, err = fmt.Fprintln(connection, "OK;" + indexStr + ";")
|
_, err = fmt.Fprintln(connection, "OK;"+indexStr+";")
|
||||||
if err != nil { log.Fatal().Err(err).Msg("Error writing response") }
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Error writing response")
|
||||||
|
}
|
||||||
case "file":
|
case "file":
|
||||||
// If processedData only has one entry
|
// If processedData only has one entry
|
||||||
if len(processedData) == 1 {
|
if len(processedData) == 1 {
|
||||||
@ -114,8 +137,10 @@ func SendFiles(dir string) {
|
|||||||
log.Info().Str("file", file).Msg("File requested")
|
log.Info().Str("file", file).Msg("File requested")
|
||||||
}
|
}
|
||||||
// Write file as hex to connection
|
// Write file as hex to connection
|
||||||
_, err = fmt.Fprintln(connection, "OK;" + hex.EncodeToString(fileData) + ";")
|
_, err = fmt.Fprintln(connection, "OK;"+hex.EncodeToString(fileData)+";")
|
||||||
if err != nil { log.Fatal().Err(err).Msg("Error writing response") }
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Error writing response")
|
||||||
|
}
|
||||||
case "stop":
|
case "stop":
|
||||||
// Alert user that stop signal has been received
|
// Alert user that stop signal has been received
|
||||||
log.Info().Msg("Received stop signal")
|
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{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Request index from sender
|
// Request index from sender
|
||||||
_, err := fmt.Fprintln(connection, "index;")
|
_, 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
|
// Read received message
|
||||||
message, err := bufio.NewReader(connection).ReadString('\n')
|
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
|
// Process received message
|
||||||
procMessage := strings.Split(strings.TrimSpace(message), ";")
|
procMessage := strings.Split(strings.TrimSpace(message), ";")
|
||||||
// If non-ok code returned, fatally log
|
// 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
|
// Get index from message
|
||||||
index := strings.Split(strings.TrimSpace(procMessage[1]), "|")
|
index := strings.Split(strings.TrimSpace(procMessage[1]), "|")
|
||||||
for _, file := range index {
|
for _, file := range index {
|
||||||
// Get current file in index
|
// Get current file in index
|
||||||
_, err = fmt.Fprintln(connection, "file;" + file + ";")
|
_, err = fmt.Fprintln(connection, "file;"+file+";")
|
||||||
if err != nil { log.Fatal().Err(err).Msg("Error sending file request") }
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Error sending file request")
|
||||||
|
}
|
||||||
// Read received message
|
// Read received message
|
||||||
message, err := bufio.NewReader(connection).ReadString('\n')
|
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
|
// Process received message
|
||||||
procMessage := strings.Split(message, ";")
|
procMessage := strings.Split(message, ";")
|
||||||
// If non-ok code returned
|
// If non-ok code returned
|
||||||
if procMessage[0] != "OK" {
|
if procMessage[0] != "OK" {
|
||||||
// fatally log
|
// fatally log
|
||||||
log.Fatal().Err(err).Msg("Sender reported error")
|
log.Fatal().Err(err).Msg("Sender reported error")
|
||||||
// Otherwise
|
// Otherwise
|
||||||
} else {
|
} 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
|
// Decode file data from hex string
|
||||||
fileData, err := hex.DecodeString(strings.TrimSpace(procMessage[1]))
|
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
|
// Copy response body to new file
|
||||||
bytesWritten, err := io.Copy(newFile, bytes.NewBuffer(fileData))
|
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
|
||||||
@ -210,4 +251,4 @@ func SendSrvStopSignal(connection net.Conn) {
|
|||||||
_, _ = fmt.Fprintln(connection, "stop;")
|
_, _ = fmt.Fprintln(connection, "stop;")
|
||||||
// Close connection
|
// Close connection
|
||||||
_ = connection.Close()
|
_ = connection.Close()
|
||||||
}
|
}
|
||||||
|
32
keyCrypto.go
32
keyCrypto.go
@ -20,7 +20,9 @@ func GenerateRSAKeypair() (*rsa.PrivateKey, *rsa.PublicKey) {
|
|||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Generate private/public RSA keypair
|
// Generate private/public RSA keypair
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
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
|
// Get public key
|
||||||
publicKey := privateKey.PublicKey
|
publicKey := privateKey.PublicKey
|
||||||
// Return keypair
|
// Return keypair
|
||||||
@ -33,23 +35,31 @@ func GetKey(connection net.Conn) []byte {
|
|||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Send key request to connection
|
// Send key request to connection
|
||||||
_, err := fmt.Fprintln(connection, "key;")
|
_, 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
|
// Read received message
|
||||||
message, err := bufio.NewReader(connection).ReadString('\n')
|
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
|
// Process received message
|
||||||
procMessage := strings.Split(strings.TrimSpace(message), ";")
|
procMessage := strings.Split(strings.TrimSpace(message), ";")
|
||||||
// If ok code returned
|
// If ok code returned
|
||||||
if procMessage[0] == "OK" {
|
if procMessage[0] == "OK" {
|
||||||
// Decode received hex string into key
|
// Decode received hex string into key
|
||||||
key, err := hex.DecodeString(procMessage[1])
|
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
|
||||||
return key
|
return key
|
||||||
// Otherwise
|
// Otherwise
|
||||||
} else {
|
} else {
|
||||||
// Fatally log
|
// 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 if all else fails
|
||||||
return nil
|
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{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Encrypt shared key using RSA
|
// Encrypt shared key using RSA
|
||||||
encryptedSharedKey, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, recvPubKey, []byte(sharedKey), nil)
|
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 encrypted key
|
||||||
return encryptedSharedKey
|
return encryptedSharedKey
|
||||||
}
|
}
|
||||||
@ -70,9 +82,11 @@ func EncryptKey(sharedKey string, recvPubKey *rsa.PublicKey) []byte {
|
|||||||
func DecryptKey(encryptedKey []byte, privateKey *rsa.PrivateKey) string {
|
func DecryptKey(encryptedKey []byte, privateKey *rsa.PrivateKey) string {
|
||||||
// Decrypt shared key using RSA
|
// Decrypt shared key using RSA
|
||||||
decryptedKey, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, encryptedKey, nil)
|
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
|
// Get string of decrypted key
|
||||||
sharedKey := string(decryptedKey)
|
sharedKey := string(decryptedKey)
|
||||||
// Return shared key
|
// Return shared key
|
||||||
return sharedKey
|
return sharedKey
|
||||||
}
|
}
|
||||||
|
@ -15,20 +15,26 @@ func ReceiverKeyExchange(key *rsa.PublicKey) string {
|
|||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Hook(FatalHook{})
|
||||||
// Create TCP listener on port 9797
|
// Create TCP listener on port 9797
|
||||||
listener, err := net.Listen("tcp", ":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
|
// Create string for sender address
|
||||||
var senderAddr string
|
var senderAddr string
|
||||||
for {
|
for {
|
||||||
// Accept connection on listener
|
// Accept connection on listener
|
||||||
connection, err := listener.Accept()
|
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
|
// Get sender address and store it in senderAddr
|
||||||
senderAddr = connection.RemoteAddr().String()
|
senderAddr = connection.RemoteAddr().String()
|
||||||
// Create gob encoder with connection as io.Writer
|
// Create gob encoder with connection as io.Writer
|
||||||
encoder := gob.NewEncoder(connection)
|
encoder := gob.NewEncoder(connection)
|
||||||
// Encode key into connection
|
// Encode key into connection
|
||||||
err = encoder.Encode(key)
|
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
|
return senderAddr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,15 +44,19 @@ func SenderKeyExchange(receiverIP string) *rsa.PublicKey {
|
|||||||
// 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{})
|
||||||
// Connect to TCP socket on receiver IP port 9797
|
// Connect to TCP socket on receiver IP port 9797
|
||||||
connection, err := net.Dial("tcp", receiverIP + ":9797")
|
connection, err := net.Dial("tcp", receiverIP+":9797")
|
||||||
if err != nil { log.Fatal().Err(err).Msg("Error connecting to sender") }
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Error connecting to sender")
|
||||||
|
}
|
||||||
// Create gob decoder
|
// Create gob decoder
|
||||||
decoder := gob.NewDecoder(connection)
|
decoder := gob.NewDecoder(connection)
|
||||||
// Instantiate rsa.PublicKey struct
|
// Instantiate rsa.PublicKey struct
|
||||||
recvPubKey := &rsa.PublicKey{}
|
recvPubKey := &rsa.PublicKey{}
|
||||||
// Decode key
|
// Decode key
|
||||||
err = decoder.Decode(recvPubKey)
|
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 received key
|
||||||
return recvPubKey
|
return recvPubKey
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Fatal hook to run in case of Fatal error
|
// Fatal hook to run in case of Fatal error
|
||||||
type FatalHook struct {}
|
type FatalHook struct{}
|
||||||
|
|
||||||
// Run function on trigger
|
// Run function on trigger
|
||||||
func (hook FatalHook) Run(_ *zerolog.Event, level zerolog.Level, _ string) {
|
func (hook FatalHook) Run(_ *zerolog.Event, level zerolog.Level, _ string) {
|
||||||
@ -36,4 +36,4 @@ func (hook TCPFatalHook) Run(_ *zerolog.Event, level zerolog.Level, _ string) {
|
|||||||
_ = os.RemoveAll(opensendDir)
|
_ = os.RemoveAll(opensendDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
30
main.go
30
main.go
@ -25,7 +25,9 @@ func main() {
|
|||||||
|
|
||||||
// Get user's home directory
|
// Get user's home directory
|
||||||
homeDir, err := os.UserHomeDir()
|
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
|
// Define opensend directory as ~/.opensend
|
||||||
opensendDir = homeDir + "/.opensend"
|
opensendDir = homeDir + "/.opensend"
|
||||||
|
|
||||||
@ -50,11 +52,11 @@ func main() {
|
|||||||
// Create --send-to flag to send to a specific IP
|
// Create --send-to flag to send to a specific IP
|
||||||
sendTo := flag.String("send-to", "", "Use IP address of receiver instead of mDNS")
|
sendTo := flag.String("send-to", "", "Use IP address of receiver instead of mDNS")
|
||||||
// Create --dest-dir flag to save to a specified folder
|
// 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
|
// Create --skip-mdns to skip service registration
|
||||||
skipMdns := flag.Bool("skip-mdns", false, "Skip zeroconf service registration (use if mdns fails)")
|
skipMdns := flag.Bool("skip-mdns", false, "Skip zeroconf service registration (use if mdns fails)")
|
||||||
// Create -t flag for type
|
// 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
|
// Create -d flag for data
|
||||||
actionData := flag.String("d", "", "Data to send")
|
actionData := flag.String("d", "", "Data to send")
|
||||||
// Create -s flag for sending
|
// Create -s flag for sending
|
||||||
@ -75,7 +77,9 @@ func main() {
|
|||||||
sharedKeyBytes := make([]byte, 32)
|
sharedKeyBytes := make([]byte, 32)
|
||||||
// Read random bytes into buffer
|
// Read random bytes into buffer
|
||||||
_, err := io.ReadFull(rand.Reader, sharedKeyBytes)
|
_, 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
|
// Encode random bytes to hexadecimal
|
||||||
sharedKey := hex.EncodeToString(sharedKeyBytes)
|
sharedKey := hex.EncodeToString(sharedKeyBytes)
|
||||||
// Notify user a key has been created
|
// Notify user a key has been created
|
||||||
@ -88,7 +92,7 @@ func main() {
|
|||||||
log.Info().Msg("IP provided. Skipping discovery.")
|
log.Info().Msg("IP provided. Skipping discovery.")
|
||||||
// Set chosen IP to provided
|
// Set chosen IP to provided
|
||||||
choiceIP = *sendTo
|
choiceIP = *sendTo
|
||||||
// Otherwise
|
// Otherwise
|
||||||
} else {
|
} else {
|
||||||
// Notify user device discovery is beginning
|
// Notify user device discovery is beginning
|
||||||
log.Info().Msg("Discovering opensend receivers")
|
log.Info().Msg("Discovering opensend receivers")
|
||||||
@ -106,7 +110,9 @@ func main() {
|
|||||||
choiceStr, _ := reader.ReadString('\n')
|
choiceStr, _ := reader.ReadString('\n')
|
||||||
// Convert input to int after trimming spaces
|
// Convert input to int after trimming spaces
|
||||||
choiceInt, err := strconv.Atoi(strings.TrimSpace(choiceStr))
|
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
|
// Set choiceIndex to choiceInt-1 to allow for indexing
|
||||||
choiceIndex := choiceInt - 1
|
choiceIndex := choiceInt - 1
|
||||||
// Get IP of chosen receiver
|
// Get IP of chosen receiver
|
||||||
@ -129,7 +135,7 @@ func main() {
|
|||||||
// Encrypt shared key using RSA public key
|
// Encrypt shared key using RSA public key
|
||||||
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")
|
||||||
// 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
|
||||||
@ -138,7 +144,7 @@ func main() {
|
|||||||
log.Info().Msg("Server started on port 9898")
|
log.Info().Msg("Server started on port 9898")
|
||||||
// Send all files in opensend directory using an HTTP server on port 9898
|
// Send all files in opensend directory using an HTTP server on port 9898
|
||||||
SendFiles(opensendDir)
|
SendFiles(opensendDir)
|
||||||
// If -r given
|
// If -r given
|
||||||
} else if *recvFlag {
|
} else if *recvFlag {
|
||||||
// If --skip-mdns is not given
|
// If --skip-mdns is not given
|
||||||
if !*skipMdns {
|
if !*skipMdns {
|
||||||
@ -156,7 +162,7 @@ func main() {
|
|||||||
// Exchange keys with sender
|
// Exchange keys with sender
|
||||||
senderIP := ReceiverKeyExchange(publicKey)
|
senderIP := ReceiverKeyExchange(publicKey)
|
||||||
// Sleep 300ms to allow sender time to start HTTP server
|
// 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
|
// 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
|
// Connect to sender's TCP socket
|
||||||
@ -187,5 +193,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
// Remove opensend directory
|
// Remove opensend directory
|
||||||
err = os.RemoveAll(opensendDir)
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user