Author SHA1 Message Date
Milan Stute cbc7ca46a7 Bump version 2021-04-29 14:59:52 +02:00
Milan Stute df221b0e2b Fixup: autoformat 2021-04-29 14:55:39 +02:00
Milan Stute 4f1849cea2 Add sending support for URLs (fixes #67) 2021-04-29 14:55:04 +02:00
Milan Stute 8bacbe97b0 Add PrivateDrop reference 2021-04-29 12:47:38 +02:00
4 changed files with 39 additions and 23 deletions
+11 -3
View File
@@ -52,7 +52,7 @@ pip3 install ./opendrop
We briefly explain how to send and receive files using `opendrop`.
To see all command line options, run `opendrop -h`.
### Sending a File
### Sending a File or a Link
Sending a file is typically a two-step procedure. You first discover devices in proximity using the `find` command.
Stop the process once you have found the receiver.
@@ -62,7 +62,7 @@ Looking for receivers. Press Ctrl+C to stop ...
Found index 0 ID eccb2f2dcfe7 name Johns iPhone
Found index 1 ID e63138ac6ba8 name Janes MacBook Pro
```
You can then `send` a file using
You can then `send` a file (or link, see below) using
```
$ opendrop send -r 0 -f /path/to/some/file
Asking receiver to accept ...
@@ -73,6 +73,13 @@ Uploading has been successful
Instead of the `index`, you can also use `ID` or `name`.
OpenDrop will try to interpret the input in the order (1) `index`, (2) `ID`, and (3) `name` and fail if no match was found.
**Sending a web link.** Since v0.13, OpenDrop supports sending web links, i.e., URLs, so that receiving Apple devices will immediately open their browser upon accepting.
(Note that OpenDrop _receivers_ still only support receiving regular files.)
```
$ opendrop send -r 0 -f https://owlink.org --url
```
### Receiving Files
Receiving is much easier. Simply use the `receive` command. OpenDrop will accept all incoming files automatically and put received files in the current directory.
@@ -94,7 +101,8 @@ OpenDrop is the result of a research project and, thus, has several limitations
## Our Papers
* Milan Stute, Sashank Narain, Alex Mariotto, Alexander Heinrich, David Kreitschmann, Guevara Noubir, and Matthias Hollick. **A Billion Open Interfaces for Eve and Mallory: MitM, DoS, and Tracking Attacks on iOS and macOS Through Apple Wireless Direct Link.** *28th USENIX Security Symposium (USENIX Security 19)*, August 1416, 2019, Santa Clara, CA, USA. [Link](https://www.usenix.org/conference/usenixsecurity19/presentation/stute)
* Alexander Heinrich, Matthias Hollick, Thomas Schneider, Milan Stute, and Christian Weinert. **PrivateDrop: Practical Privacy-Preserving Authentication for Apple AirDrop.** *30th USENIX Security Symposium (USENIX Security 21)*, August 1416, 2019, virtual Event. [Paper](https://www.usenix.org/conference/usenixsecurity21/presentation/heinrich) [Website](https://privatedrop.github.io) [Code](https://github.com/seemoo-lab/privatedrop)
* Milan Stute, Sashank Narain, Alex Mariotto, Alexander Heinrich, David Kreitschmann, Guevara Noubir, and Matthias Hollick. **A Billion Open Interfaces for Eve and Mallory: MitM, DoS, and Tracking Attacks on iOS and macOS Through Apple Wireless Direct Link.** *28th USENIX Security Symposium (USENIX Security 19)*, August 1416, 2019, Santa Clara, CA, USA. [Paper](https://www.usenix.org/conference/usenixsecurity19/presentation/stute)
## Authors
+1 -1
View File
@@ -21,7 +21,7 @@ import logging
import os
import platform
__version__ = "0.12.3"
__version__ = "0.13.0"
if platform.system() == "Darwin":
dyld_path = os.environ.get("DYLD_LIBRARY_PATH", "") # save old path
+7 -3
View File
@@ -41,6 +41,9 @@ class AirDropCli:
parser = argparse.ArgumentParser()
parser.add_argument("action", choices=["receive", "find", "send"])
parser.add_argument("-f", "--file", help="File to be sent")
parser.add_argument(
"-u", "--url", help="'-f,--file is a URL", action="store_true"
)
parser.add_argument(
"-r",
"--receiver",
@@ -99,9 +102,10 @@ class AirDropCli:
else: # args.action == 'send'
if args.file is None:
parser.error("Need -f,--file when using send")
if not os.path.isfile(args.file):
if not os.path.isfile(args.file) and not args.url:
parser.error("File in -f,--file not found")
self.file = args.file
self.is_url = args.url
if args.receiver is None:
parser.error("Need -r,--receiver when using send")
self.receiver = args.receiver
@@ -184,12 +188,12 @@ class AirDropCli:
return
self.client = AirDropClient(self.config, (info["address"], info["port"]))
logger.info("Asking receiver to accept ...")
if not self.client.send_ask(self.file):
if not self.client.send_ask(self.file, is_url=self.is_url):
logger.warning("Receiver declined")
return
logger.info("Receiver accepted")
logger.info("Uploading file ...")
if not self.client.send_upload(self.file):
if not self.client.send_upload(self.file, is_url=self.is_url):
logger.warning("Uploading has failed")
return
logger.info("Uploading has been successful")
+20 -16
View File
@@ -144,7 +144,7 @@ class AirDropClient:
# if name is returned, then receiver is discoverable
return response.get("ReceiverComputerName")
def send_ask(self, file_path, icon=None):
def send_ask(self, file_path, is_url=False, icon=None):
ask_body = {
"SenderComputerName": self.config.computer_name,
"BundleID": "com.apple.finder",
@@ -155,18 +155,6 @@ class AirDropClient:
if self.config.record_data:
ask_body["SenderRecordData"] = self.config.record_data
if isinstance(file_path, str):
file_path = [file_path]
# generate icon for first file
with open(file_path[0], "rb") as f:
file_header = f.read(128)
flp = fleep.get(file_header)
if not icon and len(flp.mime) > 0 and "image" in flp.mime[0]:
icon = AirDropUtil.generate_file_icon(f.name)
if icon:
ask_body["FileIcon"] = icon
def file_entries(files):
for file in files:
file_name = os.path.basename(file)
@@ -179,8 +167,20 @@ class AirDropClient:
}
yield file_entry
ask_body["Files"] = [e for e in file_entries(file_path)]
ask_body["Items"] = []
if isinstance(file_path, str):
file_path = [file_path]
if is_url:
ask_body["Items"] = file_path
else:
# generate icon for first file
with open(file_path[0], "rb") as f:
file_header = f.read(128)
flp = fleep.get(file_header)
if not icon and len(flp.mime) > 0 and "image" in flp.mime[0]:
icon = AirDropUtil.generate_file_icon(f.name)
ask_body["Files"] = [e for e in file_entries(file_path)]
if icon:
ask_body["FileIcon"] = icon
ask_binary = plistlib.dumps(
ask_body, fmt=plistlib.FMT_BINARY # pylint: disable=no-member
@@ -189,10 +189,14 @@ class AirDropClient:
return success
def send_upload(self, file_path):
def send_upload(self, file_path, is_url=False):
"""
Send a file to a receiver.
"""
# Don't send an upload request if we just sent a link
if is_url:
return
headers = {
"Content-Type": "application/x-cpio",
}