diff --git a/.circleci/config.yml b/.circleci/config.yml index 3a63d743..4555d3ca 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,14 +7,13 @@ workflows: version: 2 test: jobs: - - test-3.5 - test-3.6 - test-3.7 jobs: - test-3.5: &test-template + test-3.6: &test-template docker: - - image: circleci/python:3.5.6 + - image: circleci/python:3.6.6 working_directory: ~/repo @@ -44,11 +43,6 @@ jobs: command: | xvfb-run -s "-screen 0 1280x1024x24" pytest --rungui --cov=onionshare --cov=onionshare_gui --cov-report=term-missing -vvv --no-qt-log tests/ - test-3.6: - <<: *test-template - docker: - - image: circleci/python:3.6.6 - test-3.7: <<: *test-template docker: diff --git a/onionshare/__init__.py b/onionshare/__init__.py index 108ffd0b..a2d6d4a1 100644 --- a/onionshare/__init__.py +++ b/onionshare/__init__.py @@ -31,9 +31,9 @@ from .onionshare import OnionShare def build_url(common, app, web): # Build the URL if common.settings.get("public_mode"): - return "http://{0:s}".format(app.onion_host) + return f"http://{app.onion_host}" else: - return "http://onionshare:{0:s}@{1:s}".format(web.password, app.onion_host) + return f"http://onionshare:{web.password}@{app.onion_host}" def main(cwd=None): @@ -44,7 +44,7 @@ def main(cwd=None): common = Common() # Display OnionShare banner - print("OnionShare {0:s} | https://onionshare.org/".format(common.version)) + print(f"OnionShare {common.version} | https://onionshare.org/") # OnionShare CLI in OSX needs to change current working directory (#132) if common.platform == "Darwin": @@ -160,10 +160,10 @@ def main(cwd=None): valid = True for filename in filenames: if not os.path.isfile(filename) and not os.path.isdir(filename): - print("{0:s} is not a valid file.".format(filename)) + print(f"{filename} is not a valid file.") valid = False if not os.access(filename, os.R_OK): - print("{0:s} is not a readable file.".format(filename)) + print(f"{filename} is not a readable file.") valid = False if not valid: sys.exit() @@ -217,9 +217,7 @@ def main(cwd=None): schedule = datetime.now() + timedelta(seconds=autostart_timer) if mode == "receive": print( - "Files sent to you appear in this folder: {}".format( - common.settings.get("data_dir") - ) + f"Files sent to you appear in this folder: {common.settings.get('data_dir')}" ) print("") print( @@ -228,30 +226,22 @@ def main(cwd=None): print("") if stealth: print( - "Give this address and HidServAuth lineto your sender, and tell them it won't be accessible until: {}".format( - schedule.strftime("%I:%M:%S%p, %b %d, %y") - ) + f"Give this address and HidServAuth lineto your sender, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}" ) print(app.auth_string) else: print( - "Give this address to your sender, and tell them it won't be accessible until: {}".format( - schedule.strftime("%I:%M:%S%p, %b %d, %y") - ) + f"Give this address to your sender, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}" ) else: if stealth: print( - "Give this address and HidServAuth line to your recipient, and tell them it won't be accessible until: {}".format( - schedule.strftime("%I:%M:%S%p, %b %d, %y") - ) + f"Give this address and HidServAuth line to your recipient, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}" ) print(app.auth_string) else: print( - "Give this address to your recipient, and tell them it won't be accessible until: {}".format( - schedule.strftime("%I:%M:%S%p, %b %d, %y") - ) + f"Give this address to your recipient, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}" ) print(url) print("") @@ -324,9 +314,7 @@ def main(cwd=None): else: if mode == "receive": print( - "Files sent to you appear in this folder: {}".format( - common.settings.get("data_dir") - ) + f"Files sent to you appear in this folder: {common.settings.get('data_dir')}" ) print("") print( diff --git a/onionshare/common.py b/onionshare/common.py index 3373462b..0a193d23 100644 --- a/onionshare/common.py +++ b/onionshare/common.py @@ -63,9 +63,9 @@ class Common(object): if self.verbose: timestamp = time.strftime("%b %d %Y %X") - final_msg = "[{}] {}.{}".format(timestamp, module, func) + final_msg = f"[{timestamp}] {module}.{func}" if msg: - final_msg = "{}: {}".format(final_msg, msg) + final_msg = f"{final_msg}: {msg}" print(final_msg) def get_resource_path(self, filename): @@ -162,7 +162,7 @@ class Common(object): if self.platform == "Windows": try: appdata = os.environ["APPDATA"] - onionshare_data_dir = "{}\\OnionShare".format(appdata) + onionshare_data_dir = f"{appdata}\\OnionShare" except: # If for some reason we don't have the 'APPDATA' environment variable # (like running tests in Linux while pretending to be in Windows) @@ -437,7 +437,7 @@ class Common(object): """ thresh = 1024.0 if b < thresh: - return "{:.1f} B".format(b) + return f"{b} B" units = ("KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB") u = 0 b /= thresh @@ -517,7 +517,7 @@ class AutoStopTimer(threading.Thread): def run(self): self.common.log( - "AutoStopTimer", "Server will shut down after {} seconds".format(self.time) + "AutoStopTimer", f"Server will shut down after {self.time} seconds" ) time.sleep(self.time) return 1 diff --git a/onionshare/onion.py b/onionshare/onion.py index 727cf5f1..4e1491eb 100644 --- a/onionshare/onion.py +++ b/onionshare/onion.py @@ -219,9 +219,7 @@ class Onion(object): dir=self.common.build_data_dir() ) self.common.log( - "Onion", - "connect", - "tor_data_directory={}".format(self.tor_data_directory.name), + "Onion", "connect", f"tor_data_directory={self.tor_data_directory.name}" ) # Create the torrc @@ -283,9 +281,7 @@ class Onion(object): # Bridge support if self.settings.get("tor_bridges_use_obfs4"): f.write( - "ClientTransportPlugin obfs4 exec {}\n".format( - self.obfs4proxy_file_path - ) + f"ClientTransportPlugin obfs4 exec {self.obfs4proxy_file_path}\n" ) with open( self.common.get_resource_path("torrc_template-obfs4") @@ -294,9 +290,7 @@ class Onion(object): f.write(line) elif self.settings.get("tor_bridges_use_meek_lite_azure"): f.write( - "ClientTransportPlugin meek_lite exec {}\n".format( - self.obfs4proxy_file_path - ) + f"ClientTransportPlugin meek_lite exec {self.obfs4proxy_file_path}\n" ) with open( self.common.get_resource_path("torrc_template-meek_lite_azure") @@ -307,17 +301,13 @@ class Onion(object): if self.settings.get("tor_bridges_use_custom_bridges"): if "obfs4" in self.settings.get("tor_bridges_use_custom_bridges"): f.write( - "ClientTransportPlugin obfs4 exec {}\n".format( - self.obfs4proxy_file_path - ) + f"ClientTransportPlugin obfs4 exec {self.obfs4proxy_file_path}\n" ) elif "meek_lite" in self.settings.get( "tor_bridges_use_custom_bridges" ): f.write( - "ClientTransportPlugin meek_lite exec {}\n".format( - self.obfs4proxy_file_path - ) + f"ClientTransportPlugin meek_lite exec {self.obfs4proxy_file_path}\n" ) f.write(self.settings.get("tor_bridges_use_custom_bridges")) f.write("\nUseBridges 1") @@ -372,9 +362,7 @@ class Onion(object): # "\033[K" clears the rest of the line print( - "Connecting to the Tor network: {}% - {}{}".format( - progress, summary, "\033[K" - ), + f"Connecting to the Tor network: {progress}% - {summary}\033[K", end="\r", ) @@ -457,12 +445,12 @@ class Onion(object): if not found_tor: try: if self.common.platform == "Linux" or self.common.platform == "BSD": - socket_file_path = "/run/user/{}/Tor/control.socket".format( - os.geteuid() + socket_file_path = ( + f"/run/user/{os.geteuid()}/Tor/control.socket" ) elif self.common.platform == "Darwin": - socket_file_path = "/run/user/{}/Tor/control.socket".format( - os.geteuid() + socket_file_path = ( + f"/run/user/{os.geteuid()}/Tor/control.socket" ) elif self.common.platform == "Windows": # Windows doesn't support unix sockets @@ -542,7 +530,7 @@ class Onion(object): # Get the tor version self.tor_version = self.c.get_version().version_str self.common.log( - "Onion", "connect", "Connected to tor {}".format(self.tor_version) + "Onion", "connect", f"Connected to tor {self.tor_version}" ) # Do the versions of stem and tor that I'm using support ephemeral onion services? @@ -597,7 +585,7 @@ class Onion(object): raise TorTooOld(strings._("error_stealth_not_supported")) if not save_scheduled_key: - print("Setting up onion service on port {0:d}.".format(int(port))) + print(f"Setting up onion service on port {port}." if self.stealth: if self.settings.get("hidservauth_string"): @@ -648,10 +636,10 @@ class Onion(object): basic_auth = None self.stealth = False - debug_message = "key_type={}".format(key_type) + debug_message = f"key_type={key_type}" if key_type == "NEW": - debug_message += ", key_content={}".format(key_content) - self.common.log("Onion", "start_onion_service", "{}".format(debug_message)) + debug_message += f", key_content={key_content}" + self.common.log("Onion", "start_onion_service", debug_message) try: if basic_auth != None: res = self.c.create_ephemeral_hidden_service( @@ -700,25 +688,19 @@ class Onion(object): self.auth_string = self.settings.get("hidservauth_string") else: auth_cookie = list(res.client_auth.values())[0] - self.auth_string = "HidServAuth {} {}".format( - onion_host, auth_cookie - ) + self.auth_string = f"HidServAuth {onion_host} {auth_cookie}" self.settings.set("hidservauth_string", self.auth_string) else: if not self.scheduled_auth_cookie: auth_cookie = list(res.client_auth.values())[0] - self.auth_string = "HidServAuth {} {}".format( - onion_host, auth_cookie - ) + self.auth_string = f"HidServAuth {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 - ) + self.auth_string = f"HidServAuth {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 @@ -741,14 +723,14 @@ class Onion(object): for onion in onions: try: self.common.log( - "Onion", "cleanup", "trying to remove onion {}".format(onion) + "Onion", "cleanup", f"trying to remove onion {onion}" ) self.c.remove_ephemeral_hidden_service(onion) except: self.common.log( "Onion", "cleanup", - "could not remove onion {}.. moving on anyway".format(onion), + f"could not remove onion {onion}.. moving on anyway", ) pass except: diff --git a/onionshare/onionshare.py b/onionshare/onionshare.py index 41a4e5a8..955f813d 100644 --- a/onionshare/onionshare.py +++ b/onionshare/onionshare.py @@ -56,7 +56,7 @@ class OnionShare(object): self.autostop_timer_thread = None def set_stealth(self, stealth): - self.common.log("OnionShare", "set_stealth", "stealth={}".format(stealth)) + self.common.log("OnionShare", f"set_stealth", "stealth={stealth}") self.stealth = stealth self.onion.stealth = stealth @@ -83,7 +83,7 @@ class OnionShare(object): self.autostop_timer_thread = AutoStopTimer(self.common, self.autostop_timer) if self.local_only: - self.onion_host = "127.0.0.1:{0:d}".format(self.port) + self.onion_host = f"127.0.0.1:{self.port}" return self.onion_host = self.onion.start_onion_service( diff --git a/onionshare/settings.py b/onionshare/settings.py index 25a28350..00854204 100644 --- a/onionshare/settings.py +++ b/onionshare/settings.py @@ -190,9 +190,7 @@ class Settings(object): # If the settings file exists, load it if os.path.exists(self.filename): try: - self.common.log( - "Settings", "load", "Trying to load {}".format(self.filename) - ) + self.common.log("Settings", "load", f"Trying to load {self.filename}") with open(self.filename, "r") as f: self._settings = json.load(f) self.fill_in_defaults() @@ -211,9 +209,7 @@ class Settings(object): """ self.common.log("Settings", "save") open(self.filename, "w").write(json.dumps(self._settings, indent=2)) - self.common.log( - "Settings", "save", "Settings saved in {}".format(self.filename) - ) + self.common.log("Settings", "save", f"Settings saved in {self.filename}") def get(self, key): return self._settings[key] diff --git a/onionshare/strings.py b/onionshare/strings.py index 76360a42..0ea2ba24 100644 --- a/onionshare/strings.py +++ b/onionshare/strings.py @@ -36,7 +36,7 @@ def load_strings(common): translations = {} for locale in common.settings.available_locales: locale_dir = common.get_resource_path("locale") - filename = os.path.join(locale_dir, "{}.json".format(locale)) + filename = os.path.join(locale_dir, f"{locale}.json") with open(filename, encoding="utf-8") as f: translations[locale] = json.load(f) diff --git a/onionshare/web/receive_mode.py b/onionshare/web/receive_mode.py index 90f000b9..c69a821d 100644 --- a/onionshare/web/receive_mode.py +++ b/onionshare/web/receive_mode.py @@ -38,7 +38,7 @@ class ReceiveModeWeb: self.cur_history_id += 1 self.web.add_request( self.web.REQUEST_INDIVIDUAL_FILE_STARTED, - "{}".format(request.path), + request.path, {"id": history_id, "status_code": 200}, ) @@ -79,11 +79,9 @@ class ReceiveModeWeb: self.common.log( "ReceiveModeWeb", "define_routes", - "/upload, uploaded {}, saving to {}".format( - f.filename, local_path - ), + f"/upload, uploaded {f.filename}, saving to {local_path}", ) - print("\n" + "Received: {}".format(local_path)) + print(f"\nReceived: {local_path}") if request.upload_error: self.common.log( @@ -98,9 +96,7 @@ class ReceiveModeWeb: {"receive_mode_dir": request.receive_mode_dir}, ) print( - "Could not create OnionShare data folder: {}".format( - request.receive_mode_dir - ) + f"Could not create OnionShare data folder: {request.receive_mode_dir}" ) msg = "Error uploading, please inform the OnionShare user" @@ -124,7 +120,7 @@ class ReceiveModeWeb: else: msg = "Sent " for filename in filenames: - msg += "{}, ".format(filename) + msg += f"{filename}, " msg = msg.rstrip(", ") if ajax: info_flashes.append(msg) @@ -191,7 +187,7 @@ class ReceiveModeFile(object): self.onionshare_close_func = close_func self.filename = os.path.join(self.onionshare_request.receive_mode_dir, filename) - self.filename_in_progress = "{}.part".format(self.filename) + self.filename_in_progress = f"{self.filename}.part" # Open the file self.upload_error = False @@ -309,7 +305,7 @@ class ReceiveModeRequest(Request): # Keep going until we find a directory name that's available i = 1 while True: - new_receive_mode_dir = "{}-{}".format(self.receive_mode_dir, i) + new_receive_mode_dir = f"{self.receive_mode_dir}-{i}" try: os.makedirs(new_receive_mode_dir, 0o700, exist_ok=False) self.receive_mode_dir = new_receive_mode_dir @@ -333,9 +329,7 @@ class ReceiveModeRequest(Request): {"receive_mode_dir": self.receive_mode_dir}, ) print( - "Could not create OnionShare data folder: {}".format( - self.receive_mode_dir - ) + f"Could not create OnionShare data folder: {self.receive_mode_dir}" ) self.web.common.log( "ReceiveModeRequest", @@ -460,12 +454,7 @@ class ReceiveModeRequest(Request): self.previous_file = filename print( - "\r=> {:15s} {}".format( - self.web.common.human_readable_filesize( - self.progress[filename]["uploaded_bytes"] - ), - filename, - ), + f"\r=> {self.web.common.human_readable_filesize(self.progress[filename]['uploaded_bytes'])} {filename}", end="", ) diff --git a/onionshare/web/send_base_mode.py b/onionshare/web/send_base_mode.py index fe7e57f8..c2086f15 100644 --- a/onionshare/web/send_base_mode.py +++ b/onionshare/web/send_base_mode.py @@ -95,16 +95,14 @@ class SendBaseModeWeb: self.cur_history_id += 1 self.web.add_request( self.web.REQUEST_INDIVIDUAL_FILE_STARTED, - "/{}".format(path), + f"/{path}", {"id": history_id, "method": request.method, "status_code": 200}, ) breadcrumbs = [("☗", "/")] parts = path.split("/")[:-1] for i in range(len(parts)): - breadcrumbs.append( - ("{}".format(parts[i]), "/{}/".format("/".join(parts[0 : i + 1]))) - ) + breadcrumbs.append((parts[i], f"/{'/'.join(parts[0 : i + 1])}/")) breadcrumbs_leaf = breadcrumbs.pop()[0] # If filesystem_path is None, this is the root directory listing @@ -173,7 +171,6 @@ class SendBaseModeWeb: {"id": history_id, "filesize": filesize}, ) - def generate(): chunk_size = 102400 # 100kb diff --git a/onionshare/web/share_mode.py b/onionshare/web/share_mode.py index 21dea639..da20c328 100644 --- a/onionshare/web/share_mode.py +++ b/onionshare/web/share_mode.py @@ -340,8 +340,8 @@ class ZipWriter(object): if zip_filename: self.zip_filename = zip_filename else: - self.zip_filename = "{0:s}/onionshare_{1:s}.zip".format( - tempfile.mkdtemp(), self.common.random_string(4, 6) + self.zip_filename = ( + f"{tempfile.mkdtemp()}/onionshare_{self.common.random_string(4, 6)}.zip" ) self.z = zipfile.ZipFile(self.zip_filename, "w", allowZip64=True) diff --git a/onionshare/web/web.py b/onionshare/web/web.py index de2d71b5..d630060d 100644 --- a/onionshare/web/web.py +++ b/onionshare/web/web.py @@ -62,15 +62,13 @@ class Web: def __init__(self, common, is_gui, mode="share"): self.common = common - self.common.log("Web", "__init__", "is_gui={}, mode={}".format(is_gui, mode)) + self.common.log("Web", "__init__", f"is_gui={is_gui}, mode={mode}") # The flask app self.app = Flask( __name__, static_folder=self.common.get_resource_path("static"), - static_url_path="/static_".format( - self.common.random_string(16) - ), # randomize static_url_path to avoid making /static unusable + static_url_path=f"/static_{self.common.random_string(16)}", # randomize static_url_path to avoid making /static unusable template_folder=self.common.get_resource_path("templates"), ) self.app.secret_key = self.common.random_string(8) @@ -154,11 +152,11 @@ class Web: def generate_static_url_path(self): # The static URL path has a 128-bit random number in it to avoid having name # collisions with files that might be getting shared - self.static_url_path = "/static_{}".format(self.common.random_string(16)) + self.static_url_path = f"/static_{self.common.random_string(16)}" self.common.log( "Web", "generate_static_url_path", - "new static_url_path is {}".format(self.static_url_path), + f"new static_url_path is {self.static_url_path}", ) # Update the flask route to handle the new static URL path @@ -218,7 +216,7 @@ class Web: @self.app.route("/favicon.ico") def favicon(): return send_file( - "{}/img/favicon.ico".format(self.common.get_resource_path("static")) + f"{self.common.get_resource_path("static")}/img/favicon.ico" ) def error401(self): @@ -228,7 +226,7 @@ class Web: auth["username"] == "onionshare" and auth["password"] not in self.invalid_passwords ): - print("Invalid password guess: {}".format(auth["password"])) + print(f"Invalid password guess: {auth["password"]}" self.add_request(Web.REQUEST_INVALID_PASSWORD, data=auth["password"]) self.invalid_passwords.append(auth["password"]) @@ -256,7 +254,7 @@ class Web: def error404(self, history_id): self.add_request( self.REQUEST_INDIVIDUAL_FILE_STARTED, - "{}".format(request.path), + request.path, {"id": history_id, "status_code": 404}, ) @@ -269,7 +267,7 @@ class Web: def error405(self, history_id): self.add_request( self.REQUEST_INDIVIDUAL_FILE_STARTED, - "{}".format(request.path), + request.path, {"id": history_id, "status_code": 405}, ) @@ -311,21 +309,21 @@ class Web: self.common.log( "Web", "generate_password", - "persistent_password={}".format(persistent_password), + f"persistent_password={persistent_password}", ) if persistent_password != None and persistent_password != "": self.password = persistent_password self.common.log( "Web", "generate_password", - 'persistent_password sent, so password is: "{}"'.format(self.password), + f'persistent_password sent, so password is: "{self.password}"', ) else: self.password = self.common.build_password() self.common.log( "Web", "generate_password", - 'built random password: "{}"'.format(self.password), + f'built random password: "{self.password}"', ) def verbose_mode(self): @@ -362,9 +360,7 @@ class Web: self.common.log( "Web", "start", - "port={}, stay_open={}, public_mode={}, password={}".format( - port, stay_open, public_mode, password - ), + f"port={port}, stay_open={stay_open}, public_mode={public_mode}, password={password}", ) self.stay_open = stay_open @@ -398,7 +394,7 @@ class Web: # (We're putting the shutdown_password in the path as well to make routing simpler) if self.running: requests.get( - "http://127.0.0.1:{}/{}/shutdown".format(port, self.shutdown_password), + f"http://127.0.0.1:{port}/{self.shutdown_password}/shutdown", auth=requests.auth.HTTPBasicAuth("onionshare", self.password), ) diff --git a/stdeb.cfg b/stdeb.cfg index 0a200132..51ff9a0c 100644 --- a/stdeb.cfg +++ b/stdeb.cfg @@ -3,4 +3,4 @@ Package3: onionshare Depends3: python3, python3-flask, python3-flask-httpauth, python3-stem, python3-pyqt5, python3-crypto, python3-socks, python3-distutils, python-nautilus, tor, obfs4proxy Build-Depends: python3, python3-all, python3-pytest, python3-requests, python3-flask, python3-flask-httpauth, python3-stem, python3-pyqt5, python3-crypto, python3-socks, python3-distutils Suite: disco -X-Python3-Version: >= 3.5.3 +X-Python3-Version: >= 3.6