mirror of
https://github.com/onionshare/onionshare.git
synced 2025-03-03 11:49:33 -05:00
Merge master branch and fix conflicts
This commit is contained in:
commit
2eb7bca242
1
.gitignore
vendored
1
.gitignore
vendored
@ -27,6 +27,7 @@ pip-log.txt
|
|||||||
.coverage
|
.coverage
|
||||||
.tox
|
.tox
|
||||||
nosetests.xml
|
nosetests.xml
|
||||||
|
.cache
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
*.mo
|
*.mo
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
include LICENSE
|
include LICENSE
|
||||||
include README.md
|
include README.md
|
||||||
include BUILD.md
|
include BUILD.md
|
||||||
include resources/*
|
include share/*
|
||||||
include resources/images/*
|
include share/images/*
|
||||||
include resources/locale/*
|
include share/locale/*
|
||||||
include resources/html/*
|
include share/html/*
|
||||||
include install/onionshare.desktop
|
include install/onionshare.desktop
|
||||||
include install/onionshare.appdata.xml
|
include install/onionshare.appdata.xml
|
||||||
include install/onionshare80.xpm
|
include install/onionshare80.xpm
|
||||||
include install/scripts/onionshare-nautilus.py
|
include install/scripts/onionshare-nautilus.py
|
||||||
|
include test/*.py
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import locale
|
||||||
import subprocess
|
import subprocess
|
||||||
import urllib
|
import urllib
|
||||||
import gi
|
import gi
|
||||||
@ -12,7 +13,55 @@ from gi.repository import GObject
|
|||||||
# Put me in /usr/share/nautilus-python/extensions/
|
# Put me in /usr/share/nautilus-python/extensions/
|
||||||
class OnionShareExtension(GObject.GObject, Nautilus.MenuProvider):
|
class OnionShareExtension(GObject.GObject, Nautilus.MenuProvider):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
# Get the localized string for "Share via OnionShare" label
|
||||||
|
self.label = None
|
||||||
|
default_label = 'Share via OnionShare'
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Re-implement localization in python2
|
||||||
|
default_locale = 'en'
|
||||||
|
locale_dir = os.path.join(sys.prefix, 'share/onionshare/locale')
|
||||||
|
if os.path.exists(locale_dir):
|
||||||
|
# Load all translations
|
||||||
|
strings = {}
|
||||||
|
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) as f:
|
||||||
|
translations[lang] = json.load(f)
|
||||||
|
|
||||||
|
strings = translations[default_locale]
|
||||||
|
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_locale]:
|
||||||
|
if key in translations[lang]:
|
||||||
|
strings[key] = translations[lang][key]
|
||||||
|
|
||||||
|
self.label = strings['share_via_onionshare']
|
||||||
|
|
||||||
|
except:
|
||||||
|
self.label = default_label
|
||||||
|
|
||||||
|
if not self.label:
|
||||||
|
self.label = default_label
|
||||||
|
|
||||||
|
"""
|
||||||
|
# This more elegant solution will only work if nautilus is using python3, and onionshare is installed system-wide.
|
||||||
|
# But nautilus is using python2, so this is commented out.
|
||||||
|
try:
|
||||||
|
import onionshare
|
||||||
|
onionshare.strings.load_strings(onionshare.common)
|
||||||
|
self.label = onionshare.strings._('share_via_onionshare')
|
||||||
|
except:
|
||||||
|
import sys
|
||||||
|
print('python version: {}').format(sys.version)
|
||||||
|
self.label = 'Share via OnionShare'
|
||||||
|
"""
|
||||||
|
|
||||||
def url2path(self,url):
|
def url2path(self,url):
|
||||||
file_uri = url.get_activation_uri()
|
file_uri = url.get_activation_uri()
|
||||||
@ -31,7 +80,7 @@ class OnionShareExtension(GObject.GObject, Nautilus.MenuProvider):
|
|||||||
|
|
||||||
def get_file_items(self, window, files):
|
def get_file_items(self, window, files):
|
||||||
menuitem = Nautilus.MenuItem(name='OnionShare::Nautilus',
|
menuitem = Nautilus.MenuItem(name='OnionShare::Nautilus',
|
||||||
label='Share via OnionShare',
|
label=self.label,
|
||||||
tip='',
|
tip='',
|
||||||
icon='')
|
icon='')
|
||||||
menu = Nautilus.Menu()
|
menu = Nautilus.Menu()
|
||||||
|
@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import inspect
|
import inspect
|
||||||
import math
|
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import random
|
import random
|
||||||
@ -70,9 +69,12 @@ def get_resource_path(filename):
|
|||||||
if getattr(sys, 'onionshare_dev_mode', False):
|
if getattr(sys, 'onionshare_dev_mode', False):
|
||||||
# Look for resources directory relative to python file
|
# Look for resources directory relative to python file
|
||||||
prefix = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))), 'share')
|
prefix = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))), 'share')
|
||||||
|
if not os.path.exists(prefix):
|
||||||
|
# While running tests during stdeb bdist_deb, look 3 directories up for the share folder
|
||||||
|
prefix = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(prefix)))), 'share')
|
||||||
|
|
||||||
elif p == 'Linux' and sys.argv and sys.argv[0].startswith(sys.prefix):
|
elif p == 'Linux':
|
||||||
# OnionShare is installed systemwide in Linux
|
# Assume OnionShare is installed systemwide in Linux, since we're not running in dev mode
|
||||||
prefix = os.path.join(sys.prefix, 'share/onionshare')
|
prefix = os.path.join(sys.prefix, 'share/onionshare')
|
||||||
|
|
||||||
elif getattr(sys, 'frozen', False):
|
elif getattr(sys, 'frozen', False):
|
||||||
@ -144,14 +146,14 @@ def human_readable_filesize(b):
|
|||||||
"""
|
"""
|
||||||
thresh = 1024.0
|
thresh = 1024.0
|
||||||
if b < thresh:
|
if b < thresh:
|
||||||
return '{0:.1f} B'.format(b)
|
return '{:.1f} B'.format(b)
|
||||||
units = ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
|
units = ('KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')
|
||||||
u = 0
|
u = 0
|
||||||
b /= thresh
|
b /= thresh
|
||||||
while b >= thresh:
|
while b >= thresh:
|
||||||
b /= thresh
|
b /= thresh
|
||||||
u += 1
|
u += 1
|
||||||
return '{0:.1f} {1:s}'.format(round(b, 1), units[u])
|
return '{:.1f} {}'.format(b, units[u])
|
||||||
|
|
||||||
|
|
||||||
def format_seconds(seconds):
|
def format_seconds(seconds):
|
||||||
|
@ -433,6 +433,13 @@ class Onion(object):
|
|||||||
self.stealth = False
|
self.stealth = False
|
||||||
self.service_id = None
|
self.service_id = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Delete the temporary tor data directory
|
||||||
|
self.tor_data_directory.cleanup()
|
||||||
|
except AttributeError:
|
||||||
|
# Skip if cleanup was somehow run before connect
|
||||||
|
pass
|
||||||
|
|
||||||
def get_tor_socks_port(self):
|
def get_tor_socks_port(self):
|
||||||
"""
|
"""
|
||||||
Returns a (address, port) tuple for the Tor SOCKS port
|
Returns a (address, port) tuple for the Tor SOCKS port
|
||||||
|
@ -18,10 +18,13 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import platform, os, json
|
import json
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
|
||||||
from . import strings, common
|
from . import strings, common
|
||||||
|
|
||||||
|
|
||||||
class Settings(object):
|
class Settings(object):
|
||||||
"""
|
"""
|
||||||
This class stores all of the settings for OnionShare, specifically for how
|
This class stores all of the settings for OnionShare, specifically for how
|
||||||
@ -95,7 +98,7 @@ class Settings(object):
|
|||||||
try:
|
try:
|
||||||
common.log('Settings', 'load', 'Trying to load {}'.format(self.filename))
|
common.log('Settings', 'load', 'Trying to load {}'.format(self.filename))
|
||||||
with open(self.filename, 'r') as f:
|
with open(self.filename, 'r') as f:
|
||||||
self._settings = json.loads(f.read())
|
self._settings = json.load(f)
|
||||||
self.fill_in_defaults()
|
self.fill_in_defaults()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@ -17,17 +17,19 @@ GNU General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
import json, locale, os
|
import json
|
||||||
|
import locale
|
||||||
|
import os
|
||||||
|
|
||||||
strings = {}
|
strings = {}
|
||||||
|
|
||||||
|
|
||||||
def load_strings(common, default="en"):
|
def load_strings(common, default="en"):
|
||||||
"""
|
"""
|
||||||
Loads translated strings and fallback to English
|
Loads translated strings and fallback to English
|
||||||
if the translation does not exist.
|
if the translation does not exist.
|
||||||
"""
|
"""
|
||||||
global strings
|
global strings
|
||||||
p = common.get_platform()
|
|
||||||
|
|
||||||
# find locale dir
|
# find locale dir
|
||||||
locale_dir = common.get_resource_path('locale')
|
locale_dir = common.get_resource_path('locale')
|
||||||
@ -37,10 +39,9 @@ def load_strings(common, default="en"):
|
|||||||
for filename in os.listdir(locale_dir):
|
for filename in os.listdir(locale_dir):
|
||||||
abs_filename = os.path.join(locale_dir, filename)
|
abs_filename = os.path.join(locale_dir, filename)
|
||||||
lang, ext = os.path.splitext(filename)
|
lang, ext = os.path.splitext(filename)
|
||||||
if abs_filename.endswith('.json'):
|
if ext == '.json':
|
||||||
with open(abs_filename, encoding='utf-8') as f:
|
with open(abs_filename, encoding='utf-8') as f:
|
||||||
lang_json = f.read()
|
translations[lang] = json.load(f)
|
||||||
translations[lang] = json.loads(lang_json)
|
|
||||||
|
|
||||||
strings = translations[default]
|
strings = translations[default]
|
||||||
lc, enc = locale.getdefaultlocale()
|
lc, enc = locale.getdefaultlocale()
|
||||||
|
@ -17,12 +17,22 @@ GNU General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
from distutils.version import StrictVersion as Version
|
|
||||||
import queue, mimetypes, platform, os, sys, socket, logging, hmac
|
import hmac
|
||||||
|
import logging
|
||||||
|
import mimetypes
|
||||||
|
import os
|
||||||
|
import queue
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from distutils.version import LooseVersion as Version
|
||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
|
|
||||||
from flask import Flask, Response, request, render_template_string, abort, make_response
|
from flask import (
|
||||||
from flask import __version__ as flask_version
|
Flask, Response, request, render_template_string, abort, make_response,
|
||||||
|
__version__ as flask_version
|
||||||
|
)
|
||||||
|
|
||||||
from . import strings, common
|
from . import strings, common
|
||||||
|
|
||||||
@ -56,6 +66,7 @@ security_headers = [
|
|||||||
('Server', 'OnionShare')
|
('Server', 'OnionShare')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def set_file_info(filenames, processed_size_callback=None):
|
def set_file_info(filenames, processed_size_callback=None):
|
||||||
"""
|
"""
|
||||||
Using the list of filenames being shared, fill in details that the web
|
Using the list of filenames being shared, fill in details that the web
|
||||||
@ -115,6 +126,8 @@ def add_request(request_type, path, data=None):
|
|||||||
|
|
||||||
|
|
||||||
slug = None
|
slug = None
|
||||||
|
|
||||||
|
|
||||||
def generate_slug():
|
def generate_slug():
|
||||||
global slug
|
global slug
|
||||||
slug = common.build_slug()
|
slug = common.build_slug()
|
||||||
@ -123,12 +136,16 @@ download_count = 0
|
|||||||
error404_count = 0
|
error404_count = 0
|
||||||
|
|
||||||
stay_open = False
|
stay_open = False
|
||||||
|
|
||||||
|
|
||||||
def set_stay_open(new_stay_open):
|
def set_stay_open(new_stay_open):
|
||||||
"""
|
"""
|
||||||
Set stay_open variable.
|
Set stay_open variable.
|
||||||
"""
|
"""
|
||||||
global stay_open
|
global stay_open
|
||||||
stay_open = new_stay_open
|
stay_open = new_stay_open
|
||||||
|
|
||||||
|
|
||||||
def get_stay_open():
|
def get_stay_open():
|
||||||
"""
|
"""
|
||||||
Get stay_open variable.
|
Get stay_open variable.
|
||||||
@ -138,6 +155,8 @@ def get_stay_open():
|
|||||||
|
|
||||||
# Are we running in GUI mode?
|
# Are we running in GUI mode?
|
||||||
gui_mode = False
|
gui_mode = False
|
||||||
|
|
||||||
|
|
||||||
def set_gui_mode():
|
def set_gui_mode():
|
||||||
"""
|
"""
|
||||||
Tell the web service that we're running in GUI mode
|
Tell the web service that we're running in GUI mode
|
||||||
@ -145,21 +164,19 @@ def set_gui_mode():
|
|||||||
global gui_mode
|
global gui_mode
|
||||||
gui_mode = True
|
gui_mode = True
|
||||||
|
|
||||||
|
|
||||||
def debug_mode():
|
def debug_mode():
|
||||||
"""
|
"""
|
||||||
Turn on debugging mode, which will log flask errors to a debug file.
|
Turn on debugging mode, which will log flask errors to a debug file.
|
||||||
"""
|
"""
|
||||||
if platform.system() == 'Windows':
|
temp_dir = tempfile.gettempdir()
|
||||||
temp_dir = os.environ['Temp'].replace('\\', '/')
|
log_handler = logging.FileHandler(
|
||||||
else:
|
os.path.join(temp_dir, 'onionshare_server.log'))
|
||||||
temp_dir = '/tmp/'
|
|
||||||
|
|
||||||
log_handler = logging.FileHandler('{0:s}/onionshare_server.log'.format(temp_dir))
|
|
||||||
log_handler.setLevel(logging.WARNING)
|
log_handler.setLevel(logging.WARNING)
|
||||||
app.logger.addHandler(log_handler)
|
app.logger.addHandler(log_handler)
|
||||||
|
|
||||||
|
|
||||||
def check_slug_candidate(slug_candidate, slug_compare=None):
|
def check_slug_candidate(slug_candidate, slug_compare=None):
|
||||||
global slug
|
|
||||||
if not slug_compare:
|
if not slug_compare:
|
||||||
slug_compare = slug
|
slug_compare = slug
|
||||||
if not hmac.compare_digest(slug_compare, slug_candidate):
|
if not hmac.compare_digest(slug_compare, slug_candidate):
|
||||||
@ -170,6 +187,7 @@ def check_slug_candidate(slug_candidate, slug_compare = None):
|
|||||||
# one download at a time.
|
# one download at a time.
|
||||||
download_in_progress = False
|
download_in_progress = False
|
||||||
|
|
||||||
|
|
||||||
@app.route("/<slug_candidate>")
|
@app.route("/<slug_candidate>")
|
||||||
def index(slug_candidate):
|
def index(slug_candidate):
|
||||||
"""
|
"""
|
||||||
@ -202,11 +220,13 @@ def index(slug_candidate):
|
|||||||
r.headers.set(header, value)
|
r.headers.set(header, value)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
# If the client closes the OnionShare window while a download is in progress,
|
# If the client closes the OnionShare window while a download is in progress,
|
||||||
# it should immediately stop serving the file. The client_cancel global is
|
# it should immediately stop serving the file. The client_cancel global is
|
||||||
# used to tell the download function that the client is canceling the download.
|
# used to tell the download function that the client is canceling the download.
|
||||||
client_cancel = False
|
client_cancel = False
|
||||||
|
|
||||||
|
|
||||||
@app.route("/<slug_candidate>/download")
|
@app.route("/<slug_candidate>/download")
|
||||||
def download(slug_candidate):
|
def download(slug_candidate):
|
||||||
"""
|
"""
|
||||||
@ -331,11 +351,12 @@ def page_not_found(e):
|
|||||||
force_shutdown()
|
force_shutdown()
|
||||||
print(strings._('error_rate_limit'))
|
print(strings._('error_rate_limit'))
|
||||||
|
|
||||||
r = make_response(render_template_string(open(common.get_resource_path('html/404.html')).read()))
|
r = make_response(render_template_string(open(common.get_resource_path('html/404.html')).read()), 404)
|
||||||
for header, value in security_headers:
|
for header, value in security_headers:
|
||||||
r.headers.set(header, value)
|
r.headers.set(header, value)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
# shutting down the server only works within the context of flask, so the easiest way to do it is over http
|
# shutting down the server only works within the context of flask, so the easiest way to do it is over http
|
||||||
shutdown_slug = common.random_string(16)
|
shutdown_slug = common.random_string(16)
|
||||||
|
|
||||||
|
@ -434,6 +434,9 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
if not web.get_stay_open():
|
if not web.get_stay_open():
|
||||||
self.server_status.stop_server()
|
self.server_status.stop_server()
|
||||||
self.server_status.shutdown_timeout_reset()
|
self.server_status.shutdown_timeout_reset()
|
||||||
|
else:
|
||||||
|
if self.server_status.status == self.server_status.STATUS_STOPPED:
|
||||||
|
self.downloads.cancel_download(event["data"]["id"])
|
||||||
|
|
||||||
elif event["type"] == web.REQUEST_CANCELED:
|
elif event["type"] == web.REQUEST_CANCELED:
|
||||||
download_in_progress = False
|
download_in_progress = False
|
||||||
|
@ -125,7 +125,7 @@ class TorConnectionThread(QtCore.QThread):
|
|||||||
|
|
||||||
# Connect to the Onion
|
# Connect to the Onion
|
||||||
try:
|
try:
|
||||||
self.onion.connect(self.settings, self._tor_status_update)
|
self.onion.connect(self.settings, False, self._tor_status_update)
|
||||||
if self.onion.connected_to_tor:
|
if self.onion.connected_to_tor:
|
||||||
self.connected_to_tor.emit()
|
self.connected_to_tor.emit()
|
||||||
else:
|
else:
|
||||||
|
@ -118,5 +118,6 @@
|
|||||||
"gui_tor_connection_ask_quit": "Quit",
|
"gui_tor_connection_ask_quit": "Quit",
|
||||||
"gui_tor_connection_error_settings": "Try adjusting how OnionShare connects to the Tor network in Settings.",
|
"gui_tor_connection_error_settings": "Try adjusting how OnionShare connects to the Tor network in Settings.",
|
||||||
"gui_server_started_after_timeout": "The server started after your chosen auto-timeout.\nPlease start a new share.",
|
"gui_server_started_after_timeout": "The server started after your chosen auto-timeout.\nPlease start a new share.",
|
||||||
"gui_server_timeout_expired": "The chosen timeout has already expired.\nPlease update the timeout and then you may start sharing."
|
"gui_server_timeout_expired": "The chosen timeout has already expired.\nPlease update the timeout and then you may start sharing.",
|
||||||
|
"share_via_onionshare": "Share via OnionShare"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user