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($('
  • ').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(' 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 - - OnionShare - - - - - - -
    - -

    OnionShare

    -
    + + OnionShare + + + + + -
    -

    + -

    Send Files

    -

    Select the files you want to send, then click "Send Files"...

    +
    + +

    OnionShare

    +
    -
    +
    +

    -
    -
      - {% with messages = get_flashed_messages(with_categories=true) %} - {% if messages %} - {% for category, message in messages %} -
    • {{ message }}
    • - {% endfor %} - {% endif %} - {% endwith %} -
    -
    + {% if not disable_text and not disable_files %} +

    Submit Files or Messages

    +

    You can submit files, a message, or both

    + {% endif %} + {% if not disable_text and disable_files %} +

    Submit Messages

    +

    You can submit a message

    + {% endif %} + {% if disable_text and not disable_files %} +

    Submit Files

    +

    You can submit files

    + {% endif %} -
    -

    -

    -
    +
    +
    +
      + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} +
    • {{ message }}
    • + {% endfor %} + {% endif %} + {% endwith %} +
    - - - - + +
    + {% if not disable_files %} +

    + {% endif %} + {% if not disable_text %} +

    + {% endif %} +

    +
    + +
    + + + + + \ 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) + 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) - # 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, - }, - ) + with open(local_path, "w") as f: + f.write(text_message) - self.common.log( - "ReceiveModeWeb", - "define_routes", - f"/upload, uploaded {f.filename}, saving to {local_path}", - ) - print(f"\nReceived: {local_path}") + 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) - else: - flash(msg, "info") - else: - msg = "Sent " + if files_received > 0: + files_msg = "" for filename in filenames: - msg += f"{filename}, " - msg = msg.rstrip(", ") - if ajax: - info_flashes.append(msg) + 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: + if files_received > 0: + msg = f"Uploaded {files_msg}" + else: + msg = "Nothing submitted" + + if ajax: + info_flashes.append(msg) + else: + flash(msg, "info") if self.can_upload: if ajax: