Various Startup Timer fixes for strings, bundled mode, stealth mode, startup/shutdown time clashes

This commit is contained in:
Miguel Jacq 2019-03-11 15:55:17 +11:00
parent 040e7e4ca9
commit 365798b12f
No known key found for this signature in database
GPG Key ID: EEA4341C6D97A0B6
9 changed files with 123 additions and 37 deletions

View File

@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import os, sys, time, argparse, threading import os, sys, time, argparse, threading
from datetime import datetime
from datetime import timedelta
from . import strings from . import strings
from .common import Common from .common import Common
@ -137,9 +139,27 @@ def main(cwd=None):
url = 'http://{0:s}'.format(app.onion_host) url = 'http://{0:s}'.format(app.onion_host)
else: else:
url = 'http://{0:s}/{1:s}'.format(app.onion_host, web.slug) url = 'http://{0:s}/{1:s}'.format(app.onion_host, web.slug)
print(strings._("scheduled_onion_service").format(url)) schedule = datetime.now() + timedelta(seconds=startup_timer)
app.onion.cleanup() if mode == 'receive':
print(strings._("waiting_for_startup_timer")) print(strings._('receive_mode_data_dir').format(common.settings.get('data_dir')))
print('')
print(strings._('receive_mode_warning'))
print('')
if stealth:
print(strings._("give_this_scheduled_url_receive_stealth").format(schedule.strftime("%b %d, %I:%M:%S%p")))
print(app.auth_string)
else:
print(strings._("give_this_scheduled_url_receive").format(schedule.strftime("%b %d, %I:%M:%S%p")))
else:
if stealth:
print(strings._("give_this_scheduled_url_share_stealth").format(schedule.strftime("%b %d, %I:%M:%S%p")))
print(app.auth_string)
else:
print(strings._("give_this_scheduled_url_share").format(schedule.strftime("%b %d, %I:%M:%S%p")))
print(url)
print('')
print(strings._("waiting_for_scheduled_time"))
app.onion.cleanup(False)
time.sleep(startup_timer) time.sleep(startup_timer)
app.start_onion_service() app.start_onion_service()
else: else:
@ -194,27 +214,30 @@ def main(cwd=None):
url = 'http://{0:s}/{1:s}'.format(app.onion_host, web.slug) url = 'http://{0:s}/{1:s}'.format(app.onion_host, web.slug)
print('') print('')
if mode == 'receive': if startup_timer > 0:
print(strings._('receive_mode_data_dir').format(common.settings.get('data_dir'))) print(strings._('server_started'))
print('')
print(strings._('receive_mode_warning'))
print('')
if stealth:
print(strings._("give_this_url_receive_stealth"))
print(url)
print(app.auth_string)
else:
print(strings._("give_this_url_receive"))
print(url)
else: else:
if stealth: if mode == 'receive':
print(strings._("give_this_url_stealth")) print(strings._('receive_mode_data_dir').format(common.settings.get('data_dir')))
print(url) print('')
print(app.auth_string) print(strings._('receive_mode_warning'))
print('')
if stealth:
print(strings._("give_this_url_receive_stealth"))
print(url)
print(app.auth_string)
else:
print(strings._("give_this_url_receive"))
print(url)
else: else:
print(strings._("give_this_url")) if stealth:
print(url) print(strings._("give_this_url_stealth"))
print(url)
print(app.auth_string)
else:
print(strings._("give_this_url"))
print(url)
print('') print('')
print(strings._("ctrlc_to_stop")) print(strings._("ctrlc_to_stop"))

View File

@ -134,6 +134,7 @@ class Onion(object):
self.stealth = False self.stealth = False
self.service_id = None self.service_id = None
self.scheduled_key = None self.scheduled_key = None
self.scheduled_auth_cookie = None
# Is bundled tor supported? # Is bundled tor supported?
if (self.common.platform == 'Windows' or self.common.platform == 'Darwin') and getattr(sys, 'onionshare_dev_mode', False): if (self.common.platform == 'Windows' or self.common.platform == 'Darwin') and getattr(sys, 'onionshare_dev_mode', False):
@ -430,21 +431,25 @@ class Onion(object):
return the onion hostname. return the onion hostname.
""" """
self.common.log('Onion', 'start_onion_service') self.common.log('Onion', 'start_onion_service')
self.auth_string = None self.auth_string = None
if not self.supports_ephemeral: if not self.supports_ephemeral:
raise TorTooOld(strings._('error_ephemeral_not_supported')) raise TorTooOld(strings._('error_ephemeral_not_supported'))
if self.stealth and not self.supports_stealth: if self.stealth and not self.supports_stealth:
raise TorTooOld(strings._('error_stealth_not_supported')) raise TorTooOld(strings._('error_stealth_not_supported'))
print(strings._("config_onion_service").format(int(port))) if not save_scheduled_key:
print(strings._("config_onion_service").format(int(port)))
if self.stealth: if self.stealth:
if self.settings.get('hidservauth_string'): if self.settings.get('hidservauth_string'):
hidservauth_string = self.settings.get('hidservauth_string').split()[2] hidservauth_string = self.settings.get('hidservauth_string').split()[2]
basic_auth = {'onionshare':hidservauth_string} basic_auth = {'onionshare':hidservauth_string}
else: else:
basic_auth = {'onionshare':None} if self.scheduled_auth_cookie:
basic_auth = {'onionshare':self.scheduled_auth_cookie}
else:
basic_auth = {'onionshare':None}
else: else:
basic_auth = None basic_auth = None
@ -521,8 +526,19 @@ class Onion(object):
self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie) self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie)
self.settings.set('hidservauth_string', self.auth_string) self.settings.set('hidservauth_string', self.auth_string)
else: else:
auth_cookie = list(res.client_auth.values())[0] if not self.scheduled_auth_cookie:
self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie) auth_cookie = list(res.client_auth.values())[0]
self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie)
if save_scheduled_key:
# Register the HidServAuth for the scheduled share
self.scheduled_auth_cookie = auth_cookie
else:
self.scheduled_auth_cookie = None
else:
self.auth_string = 'HidServAuth {} {}'.format(onion_host, self.scheduled_auth_cookie)
if not save_scheduled_key:
# We've used the scheduled share's HidServAuth. Reset it to None for future shares
self.scheduled_auth_cookie = None
if onion_host is not None: if onion_host is not None:
self.settings.save() self.settings.save()

View File

@ -275,6 +275,7 @@ class Mode(QtWidgets.QWidget):
self.common.log('Mode', 'cancel_server: quitting startup thread') self.common.log('Mode', 'cancel_server: quitting startup thread')
self.startup_thread.canceled = True self.startup_thread.canceled = True
self.app.onion.scheduled_key = None self.app.onion.scheduled_key = None
self.app.onion.scheduled_auth_cookie = None
self.startup_thread.quit() self.startup_thread.quit()
if self.onion_thread: if self.onion_thread:
self.common.log('Mode', 'cancel_server: quitting onion thread') self.common.log('Mode', 'cancel_server: quitting onion thread')

View File

@ -205,6 +205,11 @@ class ServerStatus(QtWidgets.QWidget):
self.url.show() self.url.show()
self.copy_url_button.show() self.copy_url_button.show()
if self.app.stealth:
self.copy_hidservauth_button.show()
else:
self.copy_hidservauth_button.hide()
def update(self): def update(self):
""" """
Update the GUI elements based on the current state. Update the GUI elements based on the current state.
@ -244,11 +249,6 @@ class ServerStatus(QtWidgets.QWidget):
if self.common.settings.get('shutdown_timeout'): if self.common.settings.get('shutdown_timeout'):
self.shutdown_timeout_container.hide() self.shutdown_timeout_container.hide()
if self.app.stealth:
self.copy_hidservauth_button.show()
else:
self.copy_hidservauth_button.hide()
else: else:
self.url_description.hide() self.url_description.hide()
self.url.hide() self.url.hide()
@ -292,7 +292,8 @@ class ServerStatus(QtWidgets.QWidget):
self.server_button.setStyleSheet(self.common.css['server_status_button_working']) self.server_button.setStyleSheet(self.common.css['server_status_button_working'])
self.server_button.setEnabled(True) self.server_button.setEnabled(True)
if self.scheduled_start: if self.scheduled_start:
self.server_button.setText(strings._('gui_waiting_to_start').format(self.scheduled_start)) scheduled_friendly_time = self.startup_timer.dateTime().toString("MMM dd, H:mmAP")
self.server_button.setText(strings._('gui_waiting_to_start').format(scheduled_friendly_time))
self.startup_timer_container.hide() self.startup_timer_container.hide()
else: else:
self.server_button.setText(strings._('gui_please_wait')) self.server_button.setText(strings._('gui_please_wait'))
@ -332,6 +333,10 @@ class ServerStatus(QtWidgets.QWidget):
if QtCore.QDateTime.currentDateTime().toPyDateTime() > self.timeout: if QtCore.QDateTime.currentDateTime().toPyDateTime() > self.timeout:
can_start = False can_start = False
Alert(self.common, strings._('gui_server_timeout_expired'), QtWidgets.QMessageBox.Warning) Alert(self.common, strings._('gui_server_timeout_expired'), QtWidgets.QMessageBox.Warning)
if self.common.settings.get('startup_timer'):
if self.timeout <= self.scheduled_start:
Alert(self.common, strings._('gui_timeout_cant_be_earlier_than_startup'), QtWidgets.QMessageBox.Warning)
can_start = False
if can_start: if can_start:
self.start_server() self.start_server()
elif self.status == self.STATUS_STARTED: elif self.status == self.STATUS_STARTED:

View File

@ -75,7 +75,7 @@ class SettingsDialog(QtWidgets.QDialog):
self.startup_timer_checkbox = QtWidgets.QCheckBox() self.startup_timer_checkbox = QtWidgets.QCheckBox()
self.startup_timer_checkbox.setCheckState(QtCore.Qt.Checked) self.startup_timer_checkbox.setCheckState(QtCore.Qt.Checked)
self.startup_timer_checkbox.setText(strings._("gui_settings_startup_timer_checkbox")) self.startup_timer_checkbox.setText(strings._("gui_settings_startup_timer_checkbox"))
startup_timer_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Using-the-Auto-Stop-Timer")) startup_timer_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Using-the-Startup-Timer"))
startup_timer_label.setStyleSheet(self.common.css['settings_whats_this']) startup_timer_label.setStyleSheet(self.common.css['settings_whats_this'])
startup_timer_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction) startup_timer_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
startup_timer_label.setOpenExternalLinks(True) startup_timer_label.setOpenExternalLinks(True)

View File

@ -57,7 +57,7 @@ class OnionThread(QtCore.QThread):
time.sleep(0.2) time.sleep(0.2)
self.success_early.emit() self.success_early.emit()
# Unregister the onion so we can use it in the next OnionThread # Unregister the onion so we can use it in the next OnionThread
self.mode.app.onion.cleanup() self.mode.app.onion.cleanup(False)
else: else:
self.mode.app.start_onion_service(await_publication=True) self.mode.app.start_onion_service(await_publication=True)
# wait for modules in thread to load, preventing a thread-related cx_Freeze crash # wait for modules in thread to load, preventing a thread-related cx_Freeze crash

View File

@ -5,6 +5,11 @@
"give_this_url_stealth": "Give this address and HidServAuth line to the recipient:", "give_this_url_stealth": "Give this address and HidServAuth line to the recipient:",
"give_this_url_receive": "Give this address to the sender:", "give_this_url_receive": "Give this address to the sender:",
"give_this_url_receive_stealth": "Give this address and HidServAuth to the sender:", "give_this_url_receive_stealth": "Give this address and HidServAuth to the sender:",
"give_this_scheduled_url_share": "Give this address to your recipient, and tell them it won't be accessible until: {}",
"give_this_scheduled_url_receive": "Give this address to your sender, and tell them it won't be accessible until: {}",
"give_this_scheduled_url_share_stealth": "Give this address and HidServAuth line to your recipient, and tell them it won't be accessible until: {}",
"give_this_scheduled_url_receive_stealth": "Give this address and HidServAuth lineto your sender, and tell them it won't be accessible until: {}",
"server_started": "Server started",
"ctrlc_to_stop": "Press Ctrl+C to stop the server", "ctrlc_to_stop": "Press Ctrl+C to stop the server",
"not_a_file": "{0:s} is not a valid file.", "not_a_file": "{0:s} is not a valid file.",
"not_a_readable_file": "{0:s} is not a readable file.", "not_a_readable_file": "{0:s} is not a readable file.",
@ -126,6 +131,7 @@
"gui_server_started_after_timeout": "The auto-stop timer ran out before the server started.\nPlease make a new share.", "gui_server_started_after_timeout": "The auto-stop timer ran out before the server started.\nPlease make a new share.",
"gui_server_timeout_expired": "The auto-stop timer already ran out.\nPlease update it to start sharing.", "gui_server_timeout_expired": "The auto-stop timer already ran out.\nPlease update it to start sharing.",
"gui_server_startup_timer_expired": "The scheduled time has already passed.\nPlease update it to start sharing.", "gui_server_startup_timer_expired": "The scheduled time has already passed.\nPlease update it to start sharing.",
"gui_timeout_cant_be_earlier_than_startup": "The auto-stop time can't be the same or earlier than the start-up time.\nPlease update it to start sharing.",
"share_via_onionshare": "OnionShare it", "share_via_onionshare": "OnionShare it",
"gui_connect_to_tor_for_onion_settings": "Connect to Tor to see onion service settings", "gui_connect_to_tor_for_onion_settings": "Connect to Tor to see onion service settings",
"gui_use_legacy_v2_onions_checkbox": "Use legacy addresses", "gui_use_legacy_v2_onions_checkbox": "Use legacy addresses",
@ -188,6 +194,5 @@
"gui_share_mode_timeout_waiting": "Waiting to finish sending", "gui_share_mode_timeout_waiting": "Waiting to finish sending",
"gui_receive_mode_no_files": "No Files Received Yet", "gui_receive_mode_no_files": "No Files Received Yet",
"gui_receive_mode_timeout_waiting": "Waiting to finish receiving", "gui_receive_mode_timeout_waiting": "Waiting to finish receiving",
"waiting_for_startup_timer": "Waiting for the timer to run down before starting...", "waiting_for_scheduled_time": "Waiting for the scheduled time before starting..."
"scheduled_onion_service": "Your OnionShare URL will be: {}"
} }

View File

@ -206,6 +206,15 @@ class GuiShareTest(GuiBaseTest):
self.scheduled_service_started(self.gui.share_mode, 7000) self.scheduled_service_started(self.gui.share_mode, 7000)
self.web_server_is_running() self.web_server_is_running()
def run_all_share_mode_startup_shutdown_mismatch_tests(self, public_mode):
"""Auto-stop timer tests in share mode"""
self.run_all_share_mode_setup_tests()
self.set_startup_timer(self.gui.share_mode, 15)
self.set_timeout(self.gui.share_mode, 5)
QtCore.QTimer.singleShot(4000, self.accept_dialog)
QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton)
self.server_is_stopped(self.gui.share_mode, False)
def run_all_share_mode_unreadable_file_tests(self): def run_all_share_mode_unreadable_file_tests(self):
'''Attempt to share an unreadable file''' '''Attempt to share an unreadable file'''
self.run_all_share_mode_setup_tests() self.run_all_share_mode_setup_tests()

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
import pytest
import unittest
from .GuiShareTest import GuiShareTest
class LocalShareModeStartupTimerTest(unittest.TestCase, GuiShareTest):
@classmethod
def setUpClass(cls):
test_settings = {
"public_mode": False,
"startup_timer": True,
"shutdown_timeout": True,
}
cls.gui = GuiShareTest.set_up(test_settings)
@classmethod
def tearDownClass(cls):
GuiShareTest.tear_down()
@pytest.mark.gui
def test_gui(self):
self.run_all_common_setup_tests()
self.run_all_share_mode_startup_shutdown_mismatch_tests(False)
if __name__ == "__main__":
unittest.main()