summaryrefslogtreecommitdiff
path: root/onionshare
diff options
context:
space:
mode:
authorMiguel Jacq <mig@mig5.net>2018-11-13 14:45:40 +1100
committerMiguel Jacq <mig@mig5.net>2018-11-13 14:45:40 +1100
commitd3b5e1e256e7b122e33b98f79bf498408e1233db (patch)
tree5ac985a9da2638256b4061a90559a17e9b1dd631 /onionshare
parentdb8548c35bd5d0236c3083e9e860b82a1dbca808 (diff)
parenta39cd08083f4443e498611bbc1c086a05f5cffde (diff)
downloadonionshare-d3b5e1e256e7b122e33b98f79bf498408e1233db.tar.gz
onionshare-d3b5e1e256e7b122e33b98f79bf498408e1233db.zip
Merge develop branch and fix conflicts
Diffstat (limited to 'onionshare')
-rw-r--r--onionshare/__init__.py17
-rw-r--r--onionshare/common.py65
-rw-r--r--onionshare/onion.py2
-rw-r--r--onionshare/settings.py41
-rw-r--r--onionshare/strings.py47
-rw-r--r--onionshare/web/receive_mode.py34
-rw-r--r--onionshare/web/web.py6
7 files changed, 135 insertions, 77 deletions
diff --git a/onionshare/__init__.py b/onionshare/__init__.py
index 42294ec1..0d064639 100644
--- a/onionshare/__init__.py
+++ b/onionshare/__init__.py
@@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import os, sys, time, argparse, threading
from . import strings
-from .common import Common, DownloadsDirErrorCannotCreate, DownloadsDirErrorNotWritable
+from .common import Common
from .web import Web
from .onion import *
from .onionshare import OnionShare
@@ -33,7 +33,15 @@ def main(cwd=None):
"""
common = Common()
+ # Load the default settings and strings early, for the sake of being able to parse options.
+ # These won't be in the user's chosen locale necessarily, but we need to parse them
+ # early in order to even display the option to pass alternate settings (which might
+ # contain a preferred locale).
+ # If an alternate --config is passed, we'll reload strings later.
+ common.load_settings()
strings.load_strings(common)
+
+ # Display OnionShare banner
print(strings._('version_string').format(common.version))
# OnionShare CLI in OSX needs to change current working directory (#132)
@@ -88,8 +96,11 @@ def main(cwd=None):
if not valid:
sys.exit()
- # Load settings
- common.load_settings(config)
+ # Re-load settings, if a custom config was passed in
+ if config:
+ common.load_settings(config)
+ # Re-load the strings, in case the provided config has changed locale
+ strings.load_strings(common)
# Debug mode?
common.debug = debug
diff --git a/onionshare/common.py b/onionshare/common.py
index 28b282c2..ffa6529f 100644
--- a/onionshare/common.py
+++ b/onionshare/common.py
@@ -32,20 +32,6 @@ import time
from .settings import Settings
-class DownloadsDirErrorCannotCreate(Exception):
- """
- Error creating the downloads dir (~/OnionShare by default).
- """
- pass
-
-
-class DownloadsDirErrorNotWritable(Exception):
- """
- Downloads dir is not writable.
- """
- pass
-
-
class Common(object):
"""
The Common object is shared amongst all parts of OnionShare.
@@ -211,6 +197,7 @@ class Common(object):
color: #000000;
padding: 10px;
border: 1px solid #666666;
+ font-size: 12px;
}
""",
@@ -248,11 +235,46 @@ class Common(object):
border-radius: 5px;
}""",
+ 'downloads_uploads_empty': """
+ QWidget {
+ background-color: #ffffff;
+ border: 1px solid #999999;
+ }
+ QWidget QLabel {
+ background-color: none;
+ border: 0px;
+ }
+ """,
+
+ 'downloads_uploads_empty_text': """
+ QLabel {
+ color: #999999;
+ }""",
+
'downloads_uploads_label': """
QLabel {
font-weight: bold;
font-size 14px;
text-align: center;
+ background-color: none;
+ border: none;
+ }""",
+
+ 'downloads_uploads_clear': """
+ QPushButton {
+ color: #3f7fcf;
+ }
+ """,
+
+ 'download_uploads_indicator': """
+ QLabel {
+ color: #ffffff;
+ background-color: #f44449;
+ font-weight: bold;
+ font-size: 10px;
+ padding: 2px;
+ border-radius: 7px;
+ text-align: center;
}""",
'downloads_uploads_progress_bar': """
@@ -261,7 +283,7 @@ class Common(object):
background-color: #ffffff !important;
text-align: center;
color: #9b9b9b;
- font-size: 12px;
+ font-size: 14px;
}
QProgressBar::chunk {
background-color: #4e064f;
@@ -354,19 +376,6 @@ class Common(object):
}"""
}
- def validate_downloads_dir(self):
- """
- Validate that downloads_dir exists, and create it if it doesn't
- """
- if not os.path.isdir(self.settings.get('downloads_dir')):
- try:
- os.mkdir(self.settings.get('downloads_dir'), 0o700)
- except:
- raise DownloadsDirErrorCannotCreate
-
- if not os.access(self.settings.get('downloads_dir'), os.W_OK):
- raise DownloadsDirErrorNotWritable
-
@staticmethod
def random_string(num_bytes, output_len=None):
"""
diff --git a/onionshare/onion.py b/onionshare/onion.py
index c45ae72e..cb73e976 100644
--- a/onionshare/onion.py
+++ b/onionshare/onion.py
@@ -247,7 +247,7 @@ class Onion(object):
self.c = Controller.from_socket_file(path=self.tor_control_socket)
self.c.authenticate()
except Exception as e:
- raise BundledTorBroken(strings._('settings_error_bundled_tor_broken', True).format(e.args[0]))
+ raise BundledTorBroken(strings._('settings_error_bundled_tor_broken').format(e.args[0]))
while True:
try:
diff --git a/onionshare/settings.py b/onionshare/settings.py
index e62ccd1f..69ff50a5 100644
--- a/onionshare/settings.py
+++ b/onionshare/settings.py
@@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
import os
import platform
+import locale
from . import strings
@@ -47,6 +48,25 @@ class Settings(object):
else:
self.common.log('Settings', '__init__', 'Supplied config does not exist or is unreadable. Falling back to default location')
+ # Dictionary of available languages in this version of OnionShare,
+ # mapped to the language name, in that language
+ self.available_locales = {
+ 'cs': 'Hrvatski', # Croatian
+ 'da': 'Dansk', # Danish
+ 'de': 'Deutsch', # German
+ 'en': 'English', # English
+ 'eo': 'Esperanto', # Esperanto
+ 'es': 'Español', # Spanish
+ 'fi': 'Suomi', # Finnish
+ 'fr': 'Français', # French
+ 'it': 'Italiano', # Italian
+ 'nl': 'Nederlands', # Dutch
+ 'no': 'Norsk', # Norweigan
+ 'pt': 'Português', # Portuguese
+ 'ru': 'Русский', # Russian
+ 'tr': 'Türkçe' # Turkish
+ }
+
# These are the default settings. They will get overwritten when loading from disk
self.default_settings = {
'version': self.common.version,
@@ -73,7 +93,8 @@ class Settings(object):
'public_mode': False,
'slug': '',
'hidservauth_string': '',
- 'downloads_dir': self.build_default_downloads_dir()
+ 'downloads_dir': self.build_default_downloads_dir(),
+ 'locale': None # this gets defined in fill_in_defaults()
}
self._settings = {}
self.fill_in_defaults()
@@ -87,14 +108,26 @@ class Settings(object):
if key not in self._settings:
self._settings[key] = self.default_settings[key]
+ # Choose the default locale based on the OS preference, and fall-back to English
+ if self._settings['locale'] is None:
+ default_locale = locale.getdefaultlocale()[0][:2]
+ if default_locale not in self.available_locales:
+ default_locale = 'en'
+ self._settings['locale'] = default_locale
+
def build_filename(self):
"""
Returns the path of the settings file.
"""
p = platform.system()
if p == 'Windows':
- appdata = os.environ['APPDATA']
- return '{}\\OnionShare\\onionshare.json'.format(appdata)
+ try:
+ appdata = os.environ['APPDATA']
+ return '{}\\OnionShare\\onionshare.json'.format(appdata)
+ except:
+ # If for some reason we don't have the 'APPDATA' environment variable
+ # (like running tests in Linux while pretending to be in Windows)
+ return os.path.expanduser('~/.config/onionshare/onionshare.json')
elif p == 'Darwin':
return os.path.expanduser('~/Library/Application Support/OnionShare/onionshare.json')
else:
@@ -135,7 +168,7 @@ class Settings(object):
except:
pass
open(self.filename, 'w').write(json.dumps(self._settings))
- print(strings._('settings_saved').format(self.filename))
+ self.common.log('Settings', 'save', 'Settings saved in {}'.format(self.filename))
def get(self, key):
return self._settings[key]
diff --git a/onionshare/strings.py b/onionshare/strings.py
index 3e9df56d..b730933d 100644
--- a/onionshare/strings.py
+++ b/onionshare/strings.py
@@ -22,39 +22,36 @@ import locale
import os
strings = {}
+translations = {}
-def load_strings(common, default="en"):
+def load_strings(common):
"""
Loads translated strings and fallback to English
if the translation does not exist.
"""
- global strings
+ global strings, translations
- # find locale dir
- locale_dir = common.get_resource_path('locale')
-
- # load all translations
+ # Load all translations
translations = {}
- for filename in os.listdir(locale_dir):
- abs_filename = os.path.join(locale_dir, filename)
- lang, ext = os.path.splitext(filename)
- if ext == '.json':
- with open(abs_filename, encoding='utf-8') as f:
- translations[lang] = json.load(f)
-
- strings = translations[default]
- lc, enc = locale.getdefaultlocale()
- if lc:
- lang = lc[:2]
- if lang in translations:
- # if a string doesn't exist, fallback to English
- for key in translations[default]:
- if key in translations[lang]:
- strings[key] = translations[lang][key]
-
-
-def translated(k, gui=False):
+ for locale in common.settings.available_locales:
+ locale_dir = common.get_resource_path('locale')
+ filename = os.path.join(locale_dir, "{}.json".format(locale))
+ with open(filename, encoding='utf-8') as f:
+ translations[locale] = json.load(f)
+
+ # Build strings
+ default_locale = 'en'
+ current_locale = common.settings.get('locale')
+ strings = {}
+ for s in translations[default_locale]:
+ if s in translations[current_locale]:
+ strings[s] = translations[current_locale][s]
+ else:
+ strings[s] = translations[default_locale][s]
+
+
+def translated(k):
"""
Returns a translated string.
"""
diff --git a/onionshare/web/receive_mode.py b/onionshare/web/receive_mode.py
index 6ac96f8e..274ee138 100644
--- a/onionshare/web/receive_mode.py
+++ b/onionshare/web/receive_mode.py
@@ -4,7 +4,6 @@ from datetime import datetime
from flask import Request, request, render_template, make_response, flash, redirect
from werkzeug.utils import secure_filename
-from ..common import DownloadsDirErrorCannotCreate, DownloadsDirErrorNotWritable
from .. import strings
@@ -61,17 +60,19 @@ class ReceiveModeWeb(object):
"""
Upload files.
"""
- # Make sure downloads_dir exists
+ # Make sure the receive mode dir exists
+ now = datetime.now()
+ date_dir = now.strftime("%Y-%m-%d")
+ time_dir = now.strftime("%H.%M.%S")
+ receive_mode_dir = os.path.join(self.common.settings.get('downloads_dir'), date_dir, time_dir)
valid = True
try:
- self.common.validate_downloads_dir()
- except DownloadsDirErrorCannotCreate:
- self.web.add_request(self.web.REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE, request.path)
- print(strings._('error_cannot_create_downloads_dir').format(self.common.settings.get('downloads_dir')))
- valid = False
- except DownloadsDirErrorNotWritable:
- self.web.add_request(self.web.REQUEST_ERROR_DOWNLOADS_DIR_NOT_WRITABLE, request.path)
- print(strings._('error_downloads_dir_not_writable').format(self.common.settings.get('downloads_dir')))
+ os.makedirs(receive_mode_dir, 0o700)
+ except PermissionError:
+ self.web.add_request(self.web.REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE, request.path, {
+ "receive_mode_dir": receive_mode_dir
+ })
+ print(strings._('error_cannot_create_downloads_dir').format(receive_mode_dir))
valid = False
if not valid:
flash('Error uploading, please inform the OnionShare user', 'error')
@@ -88,7 +89,7 @@ class ReceiveModeWeb(object):
# Automatically rename the file, if a file of the same name already exists
filename = secure_filename(f.filename)
filenames.append(filename)
- local_path = os.path.join(self.common.settings.get('downloads_dir'), filename)
+ local_path = os.path.join(receive_mode_dir, filename)
if os.path.exists(local_path):
if '.' in filename:
# Add "-i", e.g. change "foo.txt" to "foo-2.txt"
@@ -100,7 +101,7 @@ class ReceiveModeWeb(object):
valid = False
while not valid:
new_filename = '{}-{}.{}'.format('.'.join(name), i, ext)
- local_path = os.path.join(self.common.settings.get('downloads_dir'), new_filename)
+ local_path = os.path.join(receive_mode_dir, new_filename)
if os.path.exists(local_path):
i += 1
else:
@@ -111,7 +112,7 @@ class ReceiveModeWeb(object):
valid = False
while not valid:
new_filename = '{}-{}'.format(filename, i)
- local_path = os.path.join(self.common.settings.get('downloads_dir'), new_filename)
+ local_path = os.path.join(receive_mode_dir, new_filename)
if os.path.exists(local_path):
i += 1
else:
@@ -126,6 +127,13 @@ class ReceiveModeWeb(object):
'new_filename': basename
})
+ # Tell the GUI the receive mode directory for this file
+ self.web.add_request(self.web.REQUEST_UPLOAD_SET_DIR, request.path, {
+ 'id': request.upload_id,
+ 'filename': basename,
+ 'dir': receive_mode_dir
+ })
+
self.common.log('ReceiveModeWeb', 'define_routes', '/upload, uploaded {}, saving to {}'.format(f.filename, local_path))
print(strings._('receive_mode_received_file').format(local_path))
f.save(local_path)
diff --git a/onionshare/web/web.py b/onionshare/web/web.py
index 45d021c0..5ecbad27 100644
--- a/onionshare/web/web.py
+++ b/onionshare/web/web.py
@@ -37,9 +37,9 @@ class Web(object):
REQUEST_RATE_LIMIT = 5
REQUEST_CLOSE_SERVER = 6
REQUEST_UPLOAD_FILE_RENAMED = 7
- REQUEST_UPLOAD_FINISHED = 8
- REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE = 9
- REQUEST_ERROR_DOWNLOADS_DIR_NOT_WRITABLE = 10
+ REQUEST_UPLOAD_SET_DIR = 8
+ REQUEST_UPLOAD_FINISHED = 9
+ REQUEST_ERROR_DOWNLOADS_DIR_CANNOT_CREATE = 10
def __init__(self, common, is_gui, mode='share'):
self.common = common