summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMicah Lee <micah@micahflee.com>2021-04-25 20:46:03 -0400
committerMicah Lee <micah@micahflee.com>2021-04-25 20:46:06 -0400
commit2acdea52298695549dfe25260ed59df88b6c3a2c (patch)
tree6f8342bfb8d6af2a1b2a912beae78ff74857cf34
parent470fb2bda3a04c856256191ceee267ce94515eef (diff)
downloadonionshare-2acdea52298695549dfe25260ed59df88b6c3a2c.tar.gz
onionshare-2acdea52298695549dfe25260ed59df88b6c3a2c.zip
Allow sending messages as well as uploading files in receive mode
-rw-r--r--cli/onionshare_cli/__init__.py21
-rw-r--r--cli/onionshare_cli/resources/static/css/style.css7
-rw-r--r--cli/onionshare_cli/resources/static/js/receive.js65
-rw-r--r--cli/onionshare_cli/resources/templates/receive.html102
-rw-r--r--cli/onionshare_cli/web/receive_mode.py145
5 files changed, 225 insertions, 115 deletions
diff --git a/cli/onionshare_cli/__init__.py b/cli/onionshare_cli/__init__.py
index 42ec9673..0a7a1d3c 100644
--- a/cli/onionshare_cli/__init__.py
+++ b/cli/onionshare_cli/__init__.py
@@ -199,6 +199,18 @@ def main(cwd=None):
default=None,
help="Receive files: URL to receive webhook notifications",
)
+ parser.add_argument(
+ "--disable-text",
+ action="store_true",
+ dest="disable_text",
+ help="Receive files: Disable receiving text messages",
+ )
+ parser.add_argument(
+ "--disable-files",
+ action="store_true",
+ dest="disable_files",
+ help="Receive files: Disable receiving files",
+ )
# Website args
parser.add_argument(
"--disable_csp",
@@ -242,6 +254,8 @@ def main(cwd=None):
autostop_sharing = not bool(args.no_autostop_sharing)
data_dir = args.data_dir
webhook_url = args.webhook_url
+ disable_text = args.disable_text
+ disable_files = args.disable_files
disable_csp = bool(args.disable_csp)
verbose = bool(args.verbose)
@@ -292,6 +306,8 @@ def main(cwd=None):
mode_settings.set("receive", "data_dir", data_dir)
if webhook_url:
mode_settings.set("receive", "webhook_url", webhook_url)
+ mode_settings.set("receive", "disable_text", disable_text)
+ mode_settings.set("receive", "disable_files", disable_files)
if mode == "website":
mode_settings.set("website", "disable_csp", disable_csp)
else:
@@ -334,6 +350,11 @@ def main(cwd=None):
if persistent_filename:
mode_settings.set(mode, "filenames", filenames)
+ # In receive mode, you must allows either text, files, or both
+ if mode == "receive" and disable_text and disable_files:
+ print(f"You cannot disable both text and files")
+ sys.exit()
+
# Create the Web object
web = Web(common, False, mode_settings, mode)
diff --git a/cli/onionshare_cli/resources/static/css/style.css b/cli/onionshare_cli/resources/static/css/style.css
index 88d9cb79..57b23fdb 100644
--- a/cli/onionshare_cli/resources/static/css/style.css
+++ b/cli/onionshare_cli/resources/static/css/style.css
@@ -285,6 +285,13 @@ ul.breadcrumbs li a:link, ul.breadcrumbs li a:visited {
margin: 0 0 20px 0;
}
+.upload-wrapper textarea {
+ max-width: 95%;
+ width: 600px;
+ height: 150px;
+ padding: 10px;
+}
+
div#uploads {
width: 800px;
max-width: 90%;
diff --git a/cli/onionshare_cli/resources/static/js/receive.js b/cli/onionshare_cli/resources/static/js/receive.js
index eac67412..f4bdedec 100644
--- a/cli/onionshare_cli/resources/static/js/receive.js
+++ b/cli/onionshare_cli/resources/static/js/receive.js
@@ -1,24 +1,35 @@
-$(function(){
+$(function () {
// Add a flash message
- var flash = function(category, message) {
+ var flash = function (category, message) {
$('#flashes').append($('<li>').addClass(category).text(message));
};
var scriptSrc = document.getElementById('receive-script').src;
- var staticImgPath = scriptSrc.substr(0, scriptSrc.lastIndexOf( '/' )+1).replace('js', 'img');
+ var staticImgPath = scriptSrc.substr(0, scriptSrc.lastIndexOf('/') + 1).replace('js', 'img');
// Intercept submitting the form
- $('#send').submit(function(event){
+ $('#send').submit(function (event) {
event.preventDefault();
- // Create form data, and list of filenames
- var files = $('#file-select').get(0).files;
- var filenames = [];
+ // Build the form data
var formData = new FormData();
- for(var i = 0; i < files.length; i++) {
- var file = files[i];
- filenames.push(file.name);
- formData.append('file[]', file, file.name);
+
+ // Files
+ var $fileSelect = $('#file-select');
+ if ($fileSelect.length > 0) {
+ var files = $fileSelect.get(0).files;
+ var filenames = [];
+ for (var i = 0; i < files.length; i++) {
+ var file = files[i];
+ filenames.push(file.name);
+ formData.append('file[]', file, file.name);
+ }
+ }
+
+ // Text message
+ var $text = $('#text');
+ if ($text.length > 0) {
+ formData.append("text", $text.val())
}
// Reset the upload form
@@ -28,9 +39,9 @@ $(function(){
// have access to the the XMLHttpRequest object
var ajax = new XMLHttpRequest();
- ajax.upload.addEventListener('progress', function(event){
+ ajax.upload.addEventListener('progress', function (event) {
// Update progress bar for this specific upload
- if(event.lengthComputable) {
+ if (event.lengthComputable) {
$('progress', ajax.$upload_div).attr({
value: event.loaded,
max: event.total,
@@ -39,13 +50,13 @@ $(function(){
// If it's finished sending all data to the first Tor node, remove cancel button
// and update the status
- if(event.loaded == event.total) {
+ if (event.loaded == event.total) {
$('.cancel', ajax.$upload_div).remove();
$('.upload-status', ajax.$upload_div).html('<img src="' + staticImgPath + '/ajax.gif" alt="" /> Waiting for data to finish traversing Tor network ...');
}
}, false);
- ajax.addEventListener('load', function(event){
+ ajax.addEventListener('load', function (event) {
// Remove the upload div
ajax.$upload_div.remove();
@@ -54,38 +65,38 @@ $(function(){
var response = JSON.parse(ajax.response);
// The 'new_body' response replaces the whole HTML document and ends
- if('new_body' in response) {
+ if ('new_body' in response) {
$('body').html(response['new_body']);
return;
}
// Show error flashes
- if('error_flashes' in response) {
- for(var i=0; i<response['error_flashes'].length; i++) {
+ if ('error_flashes' in response) {
+ for (var i = 0; i < response['error_flashes'].length; i++) {
flash('error', response['error_flashes'][i]);
}
}
// Show info flashes
- if('info_flashes' in response) {
- for(var i=0; i<response['info_flashes'].length; i++) {
+ if ('info_flashes' in response) {
+ for (var i = 0; i < response['info_flashes'].length; i++) {
flash('info', response['info_flashes'][i]);
}
}
- } catch(e) {
- flash('error', 'Invalid response from server: '+data);
+ } catch (e) {
+ flash('error', 'Invalid response from server: ' + data);
}
}, false);
- ajax.addEventListener('error', function(event){
- flash('error', 'Error uploading: '+filenames.join(', '));
+ ajax.addEventListener('error', function (event) {
+ flash('error', 'Error uploading: ' + filenames.join(', '));
// Remove the upload div
ajax.$upload_div.remove()
}, false);
- ajax.addEventListener('abort', function(event){
- flash('error', 'Upload aborted: '+filenames.join(', '));
+ ajax.addEventListener('abort', function (event) {
+ flash('error', 'Upload aborted: ' + filenames.join(', '));
}, false);
// Make the upload div
@@ -114,7 +125,7 @@ $(function(){
)
.append($progress);
- $cancel_button.click(function(){
+ $cancel_button.click(function () {
// Abort the upload, and remove the upload div
ajax.abort();
$upload_div.remove()
diff --git a/cli/onionshare_cli/resources/templates/receive.html b/cli/onionshare_cli/resources/templates/receive.html
index 20f4bb7e..507ebea6 100644
--- a/cli/onionshare_cli/resources/templates/receive.html
+++ b/cli/onionshare_cli/resources/templates/receive.html
@@ -1,46 +1,64 @@
<!DOCTYPE html>
<html>
- <head>
- <title>OnionShare</title>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link href="{{ static_url_path }}/img/favicon.ico" rel="icon" type="image/x-icon">
- <link rel="stylesheet" rel="subresource" type="text/css" href="{{ static_url_path }}/css/style.css" media="all">
- </head>
- <body>
-
- <header class="clearfix">
- <img class="logo" src="{{ static_url_path }}/img/logo.png" title="OnionShare">
- <h1>OnionShare</h1>
- </header>
-
- <div class="upload-wrapper">
- <p><img class="logo" src="{{ static_url_path }}/img/logo_large.png" title="OnionShare"></p>
-
- <p class="upload-header">Send Files</p>
- <p class="upload-description">Select the files you want to send, then click "Send Files"...</p>
-
- <div id="uploads"></div>
-
- <div>
- <ul id="flashes" class="flashes">
- {% with messages = get_flashed_messages(with_categories=true) %}
- {% if messages %}
- {% for category, message in messages %}
- <li class="{{ category }}">{{ message }}</li>
- {% endfor %}
- {% endif %}
- {% endwith %}
- </ul>
- </div>
-
- <form id="send" method="post" enctype="multipart/form-data" action="/upload">
- <p><input type="file" id="file-select" name="file[]" multiple /></p>
- <p><button type="submit" id="send-button" class="button">Send Files</button></p>
- </form>
+<head>
+ <title>OnionShare</title>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link href="{{ static_url_path }}/img/favicon.ico" rel="icon" type="image/x-icon">
+ <link rel="stylesheet" rel="subresource" type="text/css" href="{{ static_url_path }}/css/style.css" media="all">
+</head>
+
+<body>
+
+ <header class="clearfix">
+ <img class="logo" src="{{ static_url_path }}/img/logo.png" title="OnionShare">
+ <h1>OnionShare</h1>
+ </header>
+
+ <div class="upload-wrapper">
+ <p><img class="logo" src="{{ static_url_path }}/img/logo_large.png" title="OnionShare"></p>
+
+ {% if not disable_text and not disable_files %}
+ <p class="upload-header">Submit Files or Messages</p>
+ <p class="upload-description">You can submit files, a message, or both</p>
+ {% endif %}
+ {% if not disable_text and disable_files %}
+ <p class="upload-header">Submit Messages</p>
+ <p class="upload-description">You can submit a message</p>
+ {% endif %}
+ {% if disable_text and not disable_files %}
+ <p class="upload-header">Submit Files</p>
+ <p class="upload-description">You can submit files</p>
+ {% endif %}
+
+ <div id="uploads"></div>
+
+ <div>
+ <ul id="flashes" class="flashes">
+ {% with messages = get_flashed_messages(with_categories=true) %}
+ {% if messages %}
+ {% for category, message in messages %}
+ <li class="{{ category }}">{{ message }}</li>
+ {% endfor %}
+ {% endif %}
+ {% endwith %}
+ </ul>
</div>
- <script src="{{ static_url_path }}/js/jquery-3.5.1.min.js"></script>
- <script async src="{{ static_url_path }}/js/receive.js" id="receive-script"></script>
- </body>
-</html>
+
+ <form id="send" method="post" enctype="multipart/form-data" action="/upload">
+ {% if not disable_files %}
+ <p><input type="file" id="file-select" name="file[]" multiple /></p>
+ {% endif %}
+ {% if not disable_text %}
+ <p><textarea id="text" name="text" placeholder="Write a message"></textarea></p>
+ {% endif %}
+ <p><button type="submit" id="send-button" class="button">Submit</button></p>
+ </form>
+
+ </div>
+ <script src="{{ static_url_path }}/js/jquery-3.5.1.min.js"></script>
+ <script async src="{{ static_url_path }}/js/receive.js" id="receive-script"></script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/cli/onionshare_cli/web/receive_mode.py b/cli/onionshare_cli/web/receive_mode.py
index 46f471a8..f52e691e 100644
--- a/cli/onionshare_cli/web/receive_mode.py
+++ b/cli/onionshare_cli/web/receive_mode.py
@@ -64,7 +64,10 @@ class ReceiveModeWeb:
self.web.add_request(self.web.REQUEST_LOAD, request.path)
r = make_response(
render_template(
- "receive.html", static_url_path=self.web.static_url_path
+ "receive.html",
+ static_url_path=self.web.static_url_path,
+ disable_text=self.web.settings.get("receive", "disable_text"),
+ disable_files=self.web.settings.get("receive", "disable_files"),
)
)
return self.web.add_security_headers(r)
@@ -75,44 +78,88 @@ class ReceiveModeWeb:
Handle the upload files POST request, though at this point, the files have
already been uploaded and saved to their correct locations.
"""
- files = request.files.getlist("file[]")
- filenames = []
- for f in files:
- if f.filename != "":
- filename = secure_filename(f.filename)
- filenames.append(filename)
- local_path = os.path.join(request.receive_mode_dir, filename)
- basename = os.path.basename(local_path)
-
- # Tell the GUI the receive mode directory for this file
- self.web.add_request(
- self.web.REQUEST_UPLOAD_SET_DIR,
- request.path,
- {
- "id": request.history_id,
- "filename": basename,
- "dir": request.receive_mode_dir,
- },
- )
-
- self.common.log(
- "ReceiveModeWeb",
- "define_routes",
- f"/upload, uploaded {f.filename}, saving to {local_path}",
- )
- print(f"\nReceived: {local_path}")
+ text_received = False
+ if not self.web.settings.get("receive", "disable_text"):
+ text_message = request.form.get("text")
+ if text_message:
+ if text_message.strip() != "":
+ text_received = True
+ filename = "message.txt"
+ local_path = os.path.join(request.receive_mode_dir, filename)
+
+ with open(local_path, "w") as f:
+ f.write(text_message)
+
+ basename = os.path.basename(local_path)
+
+ # TODO: possibly change this
+ self.web.add_request(
+ self.web.REQUEST_UPLOAD_SET_DIR,
+ request.path,
+ {
+ "id": request.history_id,
+ "filename": basename,
+ "dir": request.receive_mode_dir,
+ },
+ )
+
+ self.common.log(
+ "ReceiveModeWeb",
+ "define_routes",
+ f"/upload, sent text message, saving to {local_path}",
+ )
+ print(f"\nReceived: {local_path}")
+
+ files_received = 0
+ if not self.web.settings.get("receive", "disable_files"):
+ files = request.files.getlist("file[]")
+
+ filenames = []
+ for f in files:
+ if f.filename != "":
+ filename = secure_filename(f.filename)
+ filenames.append(filename)
+ local_path = os.path.join(request.receive_mode_dir, filename)
+ basename = os.path.basename(local_path)
+
+ # Tell the GUI the receive mode directory for this file
+ self.web.add_request(
+ self.web.REQUEST_UPLOAD_SET_DIR,
+ request.path,
+ {
+ "id": request.history_id,
+ "filename": basename,
+ "dir": request.receive_mode_dir,
+ },
+ )
+
+ self.common.log(
+ "ReceiveModeWeb",
+ "define_routes",
+ f"/upload, uploaded {f.filename}, saving to {local_path}",
+ )
+ print(f"\nReceived: {local_path}")
+
+ files_received = len(filenames)
# Send webhook if configured
if (
- self.web.settings.get("receive", "webhook_url")
+ self.web.settings.get("receive", "webhook_url") is not None
and not request.upload_error
- and len(files) > 0
+ and (text_received or files_received)
):
- if len(files) == 1:
- file_msg = "1 file"
- else:
- file_msg = f"{len(files)} files"
- self.send_webhook_notification(f"{file_msg} uploaded to OnionShare")
+ msg = ""
+ if files_received > 0:
+ if files_received == 1:
+ msg += "1 file"
+ else:
+ msg += f"{files_received} files"
+ if text_received:
+ if msg == "":
+ msg = "A text message"
+ else:
+ msg += " and a text message"
+ self.send_webhook_notification(f"{msg} submitted to OnionShare")
if request.upload_error:
self.common.log(
@@ -140,21 +187,27 @@ class ReceiveModeWeb:
if ajax:
info_flashes = []
- if len(filenames) == 0:
- msg = "No files uploaded"
- if ajax:
- info_flashes.append(msg)
+ if files_received > 0:
+ files_msg = ""
+ for filename in filenames:
+ files_msg += f"{filename}, "
+ files_msg = files_msg.rstrip(", ")
+
+ if text_received:
+ if files_received > 0:
+ msg = f"Message submitted, uploaded {files_msg}"
else:
- flash(msg, "info")
+ msg = "Message submitted"
else:
- msg = "Sent "
- for filename in filenames:
- msg += f"{filename}, "
- msg = msg.rstrip(", ")
- if ajax:
- info_flashes.append(msg)
+ if files_received > 0:
+ msg = f"Uploaded {files_msg}"
else:
- flash(msg, "info")
+ msg = "Nothing submitted"
+
+ if ajax:
+ info_flashes.append(msg)
+ else:
+ flash(msg, "info")
if self.can_upload:
if ajax: