Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile #27

Merged
merged 17 commits into from
Aug 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PrivacyPolicy.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Flying Carpet does not send your data anywhere or collect any analytics about you, so there is no privacy policy.
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
## Version 6.0 now supports iOS!
Download [here](https://apps.apple.com/us/app/flying-carpet-file-transfer/id1637377410) or search the App Store for "Flying Carpet File Transfer." I only have so many devices to test with so if you experience bugs please submit an [issue](https://github.com/spieglt/FlyingCarpet/issues) with screenshots or output and let me know what happened.

# Flying Carpet

To download, visit the [releases](https://github.com/spieglt/FlyingCarpet/releases) page!
To download, visit the [releases](https://github.com/spieglt/FlyingCarpet/releases) page.

Wireless, encrypted file transfer over automatically configured ad hoc networking. No network infrastructure required (access point, router, switch). Just two laptops (Mac, Linux, and Windows supported) with WiFi chips in close range.
Wireless, encrypted file transfer over automatically configured ad hoc networking. No network infrastructure required (access point, router, switch). Just two computers or phones (iOS, Mac, Linux, and Windows supported) with WiFi chips in close range.

Don't have a flash drive? Don't have access to a wireless network or don't trust one? Need to move a file larger than 2GB between different filesystems but don't want to set up a file share? Try it out!

# Screenshots:

<img src="pictures/winDemo.png" width=400> <img src="pictures/macDemo.png" width=400> <img src="pictures/linuxDemo.png" width=400>
<img src="pictures/iosDemo.png" height=600> <img src="pictures/winDemo.png" height=600> <br> <img src="pictures/macDemo.png" height=600> <img src="pictures/linuxDemo.png" height=600>

# Features:

+ Cross-platform: Linux, Mac, and Windows.
+ Cross-platform: Linux, iOS, macOS, and Windows.

+ Transfer multiple files or entire folders at once, without losing progress if the transfer is interrupted or canceled.

Expand Down Expand Up @@ -41,7 +44,7 @@ chmod +x ./FlyingCarpet/flyingcarpet

**Windows:** extract `FlyingCarpetWindows.zip`, open the resulting folder, and run `flyingcarpet.exe`. You may have to click `More Info` to get past the Windows SmartScreen filter. You may also need to disable WiFi Sense.

# GUI Compilation instructions:
# GUI Compilation Instructions:

+ `go get -x github.com/spieglt/flyingcarpet`

Expand All @@ -53,7 +56,7 @@ chmod +x ./FlyingCarpet/flyingcarpet

+ Run `.\wg_rebuild.ps1` from Powershell (for Windows), `./mg_rebuild` from Terminal (for Mac), or `./lg_rebuild` (for Linux).

# CLI Compilation instructions
# CLI Compilation Instructions

+ `go get -x github.com/spieglt/flyingcarpet`

Expand All @@ -65,18 +68,20 @@ chmod +x ./FlyingCarpet/flyingcarpet

# Restrictions:

+ Apple devices can only transfer to/from Windows and Linux as they can no longer programmatically run hotspots. Use AirDrop instead.

+ 64-bit only.

+ Disables your wireless internet connection while in use (does not apply to Windows when receiving).

+ Drag-and-drop does not work on Windows because Flying Carpet requires administrator privileges on Windows and files cannot be dragged between processes of different privilege level. [See more.](https://social.msdn.microsoft.com/Forums/en-US/2fa935cf-be57-4bcc-9b96-7ee5a6b2b7a5/drag-n-drop-files-in-vista-rc1?forum=windowsuidevelopment)

+ Flying Carpet no longer works between two Macs if the receiving end is running Big Sur or newer because Apple [deprecated the necessary ad hoc WiFi functions](https://developer.apple.com/documentation/corewlan/cwinterface/1426417-startibssmode). Use AirDrop instead. Mac-to-Windows and Mac-to-Linux still work as the Linux or Windows side will always host the network.
+ Flying Carpet should rejoin you to your previous wireless network after a completed or canceled transfer. This may not happen if the program freezes, crashes, or if the windows is closed during operation.

+ Flying Carpet should rejoin you to your previous wireless network after a completed or canceled transfer. This will not happen if the program freezes, crashes, or if the windows is closed during operation.
# Planned Features:

# Planned features:
+ Android version, but I have to learn Kotlin and Android development first so it may be a while.

+ Mobile versions, integrating functionality from https://github.com/claudiodangelis/qr-filetransfer.
+ Use QR codes instead of passwords on mobile?

If you've used Flying Carpet, please send me feedback! Thank you for your interest!
If you've used Flying Carpet, please send feedback to [email protected]. Thanks for your interest!
34 changes: 24 additions & 10 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"log"
"os"
"path/filepath"
"runtime"
"strings"

"github.com/spieglt/flyingcarpet/core"
Expand Down Expand Up @@ -55,7 +56,7 @@ func getInput(cli *Cli) *core.Transfer {
var pSend = flag.Bool("send", false, "Use this flag to send files. List files last. Globs accepted. Put filenames with spaces in quotes.")
var pReceive = flag.Bool("receive", false, "Use this flag to receive files. Provide the path of a destination folder as the last argument.")
var pPort = flag.Int("port", 3290, "TCP port to use (must match on both ends).")
var pPeer = flag.String("peer", "", "Use \"-peer linux\", \"-peer mac\", or \"-peer windows\" to match the other computer.")
var pPeer = flag.String("peer", "", "Use \"-peer ios\", \"-peer linux\", \"-peer mac\", or \"-peer windows\" to match the other computer.")
flag.Parse()
about := *pAbout
send := *pSend
Expand All @@ -80,13 +81,25 @@ func getInput(cli *Cli) *core.Transfer {
switch peer {
case "linux":
t.Peer = peer
case "mac":
t.Peer = peer
case "windows":
t.Peer = peer
case "ios":
if runtime.GOOS == "darwin" {
printUsage()
log.Fatal("Must choose a [ -peer linux|windows ]. For iOS or macOS, use AirDrop.")
} else {
t.Peer = peer
}
case "mac":
if runtime.GOOS == "darwin" {
printUsage()
log.Fatal("Must choose a [ -peer linux|windows ]. For iOS or macOS, use AirDrop.")
} else {
t.Peer = peer
}
default:
printUsage()
log.Fatal("Must choose a [ -peer linux|mac|windows ].")
log.Fatal("Must choose a [ -peer linux|mac|windows|ios ].")
}

// fill out transfer struct
Expand Down Expand Up @@ -146,13 +159,14 @@ func getInput(cli *Cli) *core.Transfer {
t.DllLocation = location

// deal with password
if t.Mode == "sending" {
t.Password = getPassword()
} else if t.Mode == "receiving" {
t.IsListening()
if t.Listening {
t.Password, err = core.GeneratePassword()
if err != nil {
log.Fatal(err)
}
} else {
t.Password = getPassword()
}

return t
Expand All @@ -171,7 +185,7 @@ func adminCheck(cli *Cli) {

func getPassword() (pw string) {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter password from receiving end: ")
fmt.Print("Enter password from the other device: ")
pw, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Error getting password:", err)
Expand All @@ -183,10 +197,10 @@ func getPassword() (pw string) {
func printUsage() {
fmt.Println("\nTo send files (list files last):")
fmt.Println("(Windows) $ .\\flyingcarpet.exe -peer mac -send pic1.jpg pic35.jpg \"filename with spaces.docx\" *.txt")
fmt.Println("[Enter password from receiving end.]")
fmt.Println("[Enter password from other end, or note password to use on other end.]")
fmt.Println("\nTo receive files (specify folder last):")
fmt.Println(" (Mac) $ ./flyingcarpet -peer windows -receive ~/Downloads")
fmt.Println("[Enter password into sending end.]\n")
fmt.Println("[Enter password from other end, or note password to use on other end.]\n")
fmt.Println("Use [ -about ] flag for info and license.\n")
return
}
67 changes: 18 additions & 49 deletions core/chunker.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package core
import (
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"errors"
"fmt"
Expand Down Expand Up @@ -46,11 +46,7 @@ func sendFile(conn net.Conn, t *Transfer, expandedList []string, fileNum int, re
if err != nil {
return errors.New("Could not read file size")
}
hash, err := getHash(expandedList[fileNum])
if err != nil {
return err
}
ui.Output(fmt.Sprintf("File size: %s\nMD5 hash: %x", makeSizeReadable(fileSize), hash))
ui.Output(fmt.Sprintf("File size: %s", makeSizeReadable(fileSize)))
bytesLeft := fileSize

// set deadline for write
Expand All @@ -61,7 +57,6 @@ func sendFile(conn net.Conn, t *Transfer, expandedList []string, fileNum int, re
conn,
relPath,
fileSize,
fmt.Sprintf("%x", hash),
)

// show progress bar and start updating it
Expand Down Expand Up @@ -90,6 +85,8 @@ func sendFile(conn net.Conn, t *Transfer, expandedList []string, fileNum int, re
return err
}

// TODO: set up hasher

// send file
buffer := make([]byte, CHUNKSIZE)
for {
Expand Down Expand Up @@ -183,7 +180,7 @@ func receiveFile(conn net.Conn, t *Transfer, ui UI) error {
extendDeadline(conn)

// get file details
fileName, fileSize, fileHash, err := receiveFileDetails(conn)
fileName, fileSize, err := receiveFileDetails(conn)
if err != nil {
return err
}
Expand Down Expand Up @@ -297,16 +294,12 @@ outer:
if err != nil {
return errors.New("Could not read file size")
}
hash, err := getHash(currentFilePath)
if err != nil {
return err
}
if fmt.Sprintf("%x", hash) != fileHash {
return fmt.Errorf("Mismatched file hashes!\nHash sent at start of transfer: %x\nHash of received file: %x\nOutput size: %d",
fileHash, hash, outFileSize)
}
// hash, err := getHash(currentFilePath)
// if err != nil {
// return err
// }
ui.Output(fmt.Sprintf("Received file size: %s", makeSizeReadable(outFileSize)))
ui.Output(fmt.Sprintf("Received file hash: %x", hash))
// ui.Output(fmt.Sprintf("Received file hash: %x", hash))
ui.Output(fmt.Sprintf("Receiving took %s", time.Since(start)))

speed := (float64(outFileSize*8) / 1000000) / (float64(time.Since(start)) / 1000000000)
Expand Down Expand Up @@ -349,7 +342,7 @@ func receiveAndDecryptChunk(outFile *os.File, aesgcm cipher.AEAD, conn net.Conn)
return
}

func sendFileDetails(conn net.Conn, name string, size int64, hash string) (err error) {
func sendFileDetails(conn net.Conn, name string, size int64) (err error) {
// send size of filename
filenameLen := int64(len(name))
err = binary.Write(conn, binary.BigEndian, filenameLen)
Expand All @@ -366,52 +359,28 @@ func sendFileDetails(conn net.Conn, name string, size int64, hash string) (err e
if err != nil {
return fmt.Errorf("Error sending file size: %s", err)
}
// send size of file hash
hashSize := int64(len(hash))
err = binary.Write(conn, binary.BigEndian, hashSize)
if err != nil {
return fmt.Errorf("Error sending size of file hash: %s", err)
}
// send file hash
_, err = conn.Write([]byte(hash))
if err != nil {
return fmt.Errorf("Error sending file hash: %s", err)
}
return
}

func receiveFileDetails(conn net.Conn) (name string, size int64, hash string, err error) {
func receiveFileDetails(conn net.Conn) (name string, size int64, err error) {
// receive size of filename
var filenameLen int64
err = binary.Read(conn, binary.BigEndian, &filenameLen)
if err != nil {
return "", 0, "", fmt.Errorf("Error receiving filename length: %s", err)
return "", 0, fmt.Errorf("Error receiving filename length: %s", err)
}
// receive filename
filenameBytes := make([]byte, filenameLen)
_, err = io.ReadFull(conn, filenameBytes)
if err != nil {
return "", 0, "", fmt.Errorf("Error receiving filename: %s", err)
return "", 0, fmt.Errorf("Error receiving filename: %s", err)
}
name = string(filenameBytes)
// receive file size
err = binary.Read(conn, binary.BigEndian, &size)
if err != nil {
return "", 0, "", fmt.Errorf("Error receiving file size: %s", err)
}
// receive size of file hash
var hashSize int64
err = binary.Read(conn, binary.BigEndian, &hashSize)
if err != nil {
return "", 0, "", fmt.Errorf("Error receiving size of file hash: %s", err)
}
// receive file hash
hashBytes := make([]byte, hashSize)
_, err = io.ReadFull(conn, hashBytes)
if err != nil {
return "", 0, "", fmt.Errorf("Error receiving file hash: %s", err)
return "", 0, fmt.Errorf("Error receiving file size: %s", err)
}
hash = string(hashBytes)
return
}

Expand Down Expand Up @@ -442,16 +411,16 @@ func getSize(file *os.File) (size int64, err error) {
return
}

func getHash(filePath string) (md5hash []byte, err error) {
func getHash(filePath string) (sha256Hash []byte, err error) {
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
hash := md5.New()
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
return nil, err
}
md5hash = hash.Sum(nil)
sha256Hash = hash.Sum(nil)
return
}

Expand Down
Loading