diff --git a/cli/onionshare_cli/web/send_base_mode.py b/cli/onionshare_cli/web/send_base_mode.py index d8cef496..ca79b99f 100644 --- a/cli/onionshare_cli/web/send_base_mode.py +++ b/cli/onionshare_cli/web/send_base_mode.py @@ -131,7 +131,7 @@ class SendBaseModeWeb: self.set_file_info_custom(filenames, processed_size_callback) - def directory_listing(self, filenames, path="", filesystem_path=None): + def directory_listing(self, filenames, path="", filesystem_path=None, add_trailing_slash=False): # Tell the GUI about the directory listing history_id = self.cur_history_id self.cur_history_id += 1 @@ -150,12 +150,12 @@ class SendBaseModeWeb: breadcrumbs_leaf = breadcrumbs.pop()[0] # If filesystem_path is None, this is the root directory listing - files, dirs = self.build_directory_listing(path, filenames, filesystem_path) + files, dirs = self.build_directory_listing(path, filenames, filesystem_path, add_trailing_slash) return self.directory_listing_template( path, files, dirs, breadcrumbs, breadcrumbs_leaf ) - def build_directory_listing(self, path, filenames, filesystem_path): + def build_directory_listing(self, path, filenames, filesystem_path, add_trailing_slash=False): files = [] dirs = [] @@ -168,9 +168,14 @@ class SendBaseModeWeb: is_dir = os.path.isdir(this_filesystem_path) if is_dir: - dirs.append( - {"link": os.path.join(f"/{path}", filename), "basename": filename} - ) + if add_trailing_slash: + dirs.append( + {"link": os.path.join(f"/{path}", filename, ""), "basename": filename} + ) + else: + dirs.append( + {"link": os.path.join(f"/{path}", filename), "basename": filename} + ) else: size = os.path.getsize(this_filesystem_path) size_human = self.common.human_readable_filesize(size) diff --git a/cli/onionshare_cli/web/website_mode.py b/cli/onionshare_cli/web/website_mode.py index 1f61532b..34f5abf1 100644 --- a/cli/onionshare_cli/web/website_mode.py +++ b/cli/onionshare_cli/web/website_mode.py @@ -84,12 +84,13 @@ class WebsiteModeWeb(SendBaseModeWeb): return self.stream_individual_file(self.files[index_path]) else: - # Otherwise, render directory listing + # Otherwise, render directory listing, and enforce trailing slash + # which can help with relative asset links in sub-directories. filenames = [] for filename in os.listdir(filesystem_path): filenames.append(filename) filenames.sort() - return self.directory_listing(filenames, path, filesystem_path) + return self.directory_listing(filenames, path, filesystem_path, True) # If it's a file elif os.path.isfile(filesystem_path): @@ -112,7 +113,7 @@ class WebsiteModeWeb(SendBaseModeWeb): # Root directory listing filenames = list(self.root_files) filenames.sort() - return self.directory_listing(filenames, path) + return self.directory_listing(filenames, path, None, True) else: # If the path isn't found, throw a 404 diff --git a/desktop/README.md b/desktop/README.md index b950fec4..5814f08f 100644 --- a/desktop/README.md +++ b/desktop/README.md @@ -27,7 +27,9 @@ poetry install ### Get Tor -**Linux users:** You may need the `libxcb-xinerama0` and `libxcb-cursor0` packages installed. +**Linux users:** +- On Debian/Debian-based distributions you may need the `libxcb-xinerama0` and `libxcb-cursor0` packages installed. +- On Fedora/CentOS you may need the `libxcb-*` and `xcb-util-*` packages installed. **Windows users:** - Download and install 7-Zip (x64) from https://7-zip.org/download.html. [Add](https://medium.com/@kevinmarkvi/how-to-add-executables-togit fethc-your-path-in-windows-5ffa4ce61a53) `C:\Program Files\7-Zip` to your path. diff --git a/desktop/onionshare/gui_common.py b/desktop/onionshare/gui_common.py index e3d712f5..fcbf47f7 100644 --- a/desktop/onionshare/gui_common.py +++ b/desktop/onionshare/gui_common.py @@ -471,6 +471,10 @@ class GuiCommon: QPushButton { padding: 5px 10px; }""", + "receive_options": """ + QCheckBox:disabled { + color: #666666; + }""", # Tor Settings dialogs "tor_settings_error": """ QLabel { diff --git a/desktop/onionshare/resources/locale/en.json b/desktop/onionshare/resources/locale/en.json index a94325f0..375c4bc7 100644 --- a/desktop/onionshare/resources/locale/en.json +++ b/desktop/onionshare/resources/locale/en.json @@ -151,6 +151,7 @@ "history_requests_tooltip": "{} web requests", "error_cannot_create_data_dir": "Could not create OnionShare data folder: {}", "gui_receive_mode_warning": "Receive mode lets people upload files to your computer.

Some files can potentially take control of your computer if you open them. Only open things from people you trust, or if you know what you are doing.", + "gui_chat_mode_explainer": "Chat mode lets you chat interactively with others, in Tor Browser.

Chat history is not stored in OnionShare. The chat history will disappear when you close Tor Browser.", "gui_open_folder_error": "Could not open the folder with xdg-open. The file is here: {}", "gui_settings_language_label": "Language", "gui_settings_theme_label": "Theme", @@ -205,7 +206,7 @@ "gui_close_tab_warning_receive_description": "Close tab that is receiving files?", "gui_close_tab_warning_chat_description": "Close tab that is hosting a chat server?", "gui_close_tab_warning_website_description": "Close tab that is hosting a website?", - "gui_close_tab_warning_close": "Close", + "gui_close_tab_warning_close": "Ok", "gui_close_tab_warning_cancel": "Cancel", "gui_quit_warning_title": "Quit OnionShare?", "gui_quit_warning_description": "Quit and close all tabs, even though sharing is active in some of them?", diff --git a/desktop/onionshare/tab/mode/chat_mode/__init__.py b/desktop/onionshare/tab/mode/chat_mode/__init__.py index 01f194b1..cb4f6911 100644 --- a/desktop/onionshare/tab/mode/chat_mode/__init__.py +++ b/desktop/onionshare/tab/mode/chat_mode/__init__.py @@ -80,6 +80,11 @@ class ChatMode(Mode): header_label = QtWidgets.QLabel(strings._("gui_new_tab_chat_button")) header_label.setStyleSheet(self.common.gui.css["mode_header_label"]) + # Chat mode explainer + chat_mode_explainer = QtWidgets.QLabel(strings._("gui_chat_mode_explainer")) + chat_mode_explainer.setMinimumHeight(80) + chat_mode_explainer.setWordWrap(True) + # Top bar top_bar_layout = QtWidgets.QHBoxLayout() # Add space at the top, same height as the toggle history bar in other modes @@ -89,6 +94,7 @@ class ChatMode(Mode): self.main_layout = QtWidgets.QVBoxLayout() self.main_layout.addLayout(top_bar_layout) self.main_layout.addWidget(header_label) + self.main_layout.addWidget(chat_mode_explainer) self.main_layout.addWidget(self.primary_action, stretch=1) self.main_layout.addWidget(self.server_status) self.main_layout.addWidget(MinimumSizeWidget(700, 0)) diff --git a/desktop/onionshare/tab/mode/receive_mode/__init__.py b/desktop/onionshare/tab/mode/receive_mode/__init__.py index 87f8fc5f..bfa85459 100644 --- a/desktop/onionshare/tab/mode/receive_mode/__init__.py +++ b/desktop/onionshare/tab/mode/receive_mode/__init__.py @@ -85,12 +85,14 @@ class ReceiveMode(Mode): self.disable_text_checkbox.setText( strings._("mode_settings_receive_disable_text_checkbox") ) + self.disable_text_checkbox.setStyleSheet(self.common.gui.css["receive_options"]) self.disable_files_checkbox = self.settings.get("receive", "disable_files") self.disable_files_checkbox = QtWidgets.QCheckBox() self.disable_files_checkbox.clicked.connect(self.disable_files_checkbox_clicked) self.disable_files_checkbox.setText( strings._("mode_settings_receive_disable_files_checkbox") ) + self.disable_files_checkbox.setStyleSheet(self.common.gui.css["receive_options"]) disable_layout = QtWidgets.QHBoxLayout() disable_layout.addWidget(self.disable_text_checkbox) disable_layout.addWidget(self.disable_files_checkbox) @@ -235,11 +237,21 @@ class ReceiveMode(Mode): self.settings.set( "receive", "disable_text", self.disable_text_checkbox.isChecked() ) + if self.disable_text_checkbox.isChecked(): + # Prevent also disabling files if text is disabled + self.disable_files_checkbox.setDisabled(True) + else: + self.disable_files_checkbox.setDisabled(False) def disable_files_checkbox_clicked(self): self.settings.set( "receive", "disable_files", self.disable_files_checkbox.isChecked() ) + if self.disable_files_checkbox.isChecked(): + # Prevent also disabling text if files is disabled + self.disable_text_checkbox.setDisabled(True) + else: + self.disable_text_checkbox.setDisabled(False) def webhook_url_checkbox_clicked(self): if self.webhook_url_checkbox.isChecked():