mirror of
https://github.com/onionshare/onionshare.git
synced 2024-10-01 01:35:40 -04:00
Merge branch 'master' into ephemeral
Conflicts: onionshare/helpers.py onionshare/onionshare.py
This commit is contained in:
commit
fd39f84bff
@ -17,7 +17,7 @@ As soon as the shared files get downloaded, or when the sender closes OnionShare
|
||||
* **Third parties don't have access to files being shared.** The files are hosted directly on the sender's computer and don't get uploaded to any server. Instead, the sender's computer becomes the server. Traditional ways of sending files, like in an email or using a cloud hosting service, require trusting the service with access to the files being shared.
|
||||
* **Network eavesdroppers can't spy on files in transit.** Because connections between Tor hidden services and Tor Browser are end-to-end encrypted, no network attackers can eavesdrop on the shared files while the recipient is downloading them. If the eavesdropper is positioned on the sender's end, the recipient's end, or is a malicious Tor node, they will only see Tor traffic. If the eavesdropper is a malicious rendezvous node used to connect the recipient's Tor client with the sender's hidden service, the traffic will be encrypted using the hidden service key.
|
||||
* **Anonymity of sender and recipient are protected by Tor.** OnionShare and Tor Browser protect the anonymity of the users. As long as the sender anonymously communicates the OnionShare URL with the recipient, the recipient and eavesdroppers can't learn the identity of the sender.
|
||||
* **If an attacker enumerates the hidden service, the shared files remain safe.** There have been attacks against the Tor network that can enumerate hidden services. If someone discovers the .onion address of an OnionShare hidden service, they still cannot download the shared files without knowing the slug. The slug is generated using 16 bits of entropy, and the OnionShare server checks request URIs using a constant time string comparison function, so timing attacks can't be used to guess the slug.
|
||||
* **If an attacker enumerates the hidden service, the shared files remain safe.** There have been attacks against the Tor network that can enumerate hidden services. If someone discovers the .onion address of an OnionShare hidden service, they still cannot download the shared files without knowing the slug. The slug is generated using 16 bytes of entropy, and the OnionShare server checks request URIs using a constant time string comparison function, so timing attacks can't be used to guess the slug.
|
||||
|
||||
## What it doesn't protect against
|
||||
|
||||
|
@ -35,9 +35,12 @@
|
||||
"gui_stop_server": "Stop server",
|
||||
"gui_copy_url": "Kopier URL",
|
||||
"gui_downloads": "Downloads:",
|
||||
"gui_canceled": "Afgebroken",
|
||||
"gui_copied_url": "URL gekopieerd naar klembord",
|
||||
"gui_starting_server1": "Tor verborgen service wordt gestart...",
|
||||
"gui_starting_server2": "Bestanden verwerken...",
|
||||
"gui_starting_server3": "Wachten op Tor verborgen service...",
|
||||
"gui_please_wait": "Moment geduld..."
|
||||
"gui_please_wait": "Moment geduld...",
|
||||
"error_hs_dir_cannot_create": "Kan verborgen service map {0:s} niet aanmaken",
|
||||
"error_hs_dir_not_writable": "Verborgen service map {0:s} is niet schrijfbaar"
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ sys.setdefaultencoding("utf-8")
|
||||
|
||||
|
||||
def get_platform():
|
||||
"""
|
||||
Returns the platform OnionShare is running on.
|
||||
"""
|
||||
return platform.system()
|
||||
|
||||
if get_platform() == 'Darwin':
|
||||
@ -37,14 +40,22 @@ if get_platform() == 'Darwin':
|
||||
else:
|
||||
osx_resources_dir = None
|
||||
|
||||
|
||||
def get_onionshare_dir():
|
||||
"""
|
||||
Returns the OnionShare directory.
|
||||
"""
|
||||
if get_platform() == 'Darwin':
|
||||
onionshare_dir = os.path.dirname(__file__)
|
||||
else:
|
||||
onionshare_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||
return onionshare_dir
|
||||
|
||||
|
||||
def get_html_path(filename):
|
||||
"""
|
||||
Returns the path of the html files.
|
||||
"""
|
||||
p = platform.system()
|
||||
if p == 'Darwin':
|
||||
prefix = os.path.join(osx_resources_dir, 'html')
|
||||
@ -54,6 +65,9 @@ def get_html_path(filename):
|
||||
|
||||
|
||||
def constant_time_compare(val1, val2):
|
||||
"""
|
||||
Compares two values in constant time.
|
||||
"""
|
||||
_builtin_constant_time_compare = getattr(hmac, 'compare_digest', None)
|
||||
if _builtin_constant_time_compare is not None:
|
||||
return _builtin_constant_time_compare(val1, val2)
|
||||
@ -71,6 +85,9 @@ def constant_time_compare(val1, val2):
|
||||
|
||||
|
||||
def random_string(num_bytes, output_len=None):
|
||||
"""
|
||||
Returns a random string with a specified number of bytes.
|
||||
"""
|
||||
b = os.urandom(num_bytes)
|
||||
h = hashlib.sha256(b).digest()[:16]
|
||||
s = base64.b32encode(h).lower().replace('=', '')
|
||||
@ -80,6 +97,9 @@ def random_string(num_bytes, output_len=None):
|
||||
|
||||
|
||||
def human_readable_filesize(b):
|
||||
"""
|
||||
Returns filesize in a human readable format.
|
||||
"""
|
||||
thresh = 1024.0
|
||||
if b < thresh:
|
||||
return '{0:.1f} B'.format(b)
|
||||
@ -93,6 +113,9 @@ def human_readable_filesize(b):
|
||||
|
||||
|
||||
def is_root():
|
||||
"""
|
||||
Returns if user is root.
|
||||
"""
|
||||
return os.geteuid() == 0
|
||||
|
||||
|
||||
|
@ -26,6 +26,7 @@ class OnionShare(object):
|
||||
self.port = None
|
||||
self.hs = None
|
||||
self.hidserv_dir = None
|
||||
self.onion_host = None
|
||||
|
||||
# files and dirs to delete on shutdown
|
||||
self.cleanup_filenames = []
|
||||
|
@ -17,13 +17,17 @@ GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import json, locale, sys, os, inspect
|
||||
import json, locale, sys, os
|
||||
import helpers
|
||||
|
||||
strings = {}
|
||||
|
||||
|
||||
def load_strings(default="en"):
|
||||
"""
|
||||
Loads translated strings and fallback to English
|
||||
if the translation does not exist.
|
||||
"""
|
||||
global strings
|
||||
p = helpers.get_platform()
|
||||
|
||||
@ -36,25 +40,28 @@ def load_strings(default="en"):
|
||||
locale_dir = os.path.join(os.path.dirname(helpers.get_onionshare_dir()), 'locale')
|
||||
|
||||
# load all translations
|
||||
translated = {}
|
||||
translations = {}
|
||||
for filename in os.listdir(locale_dir):
|
||||
abs_filename = os.path.join(locale_dir, filename)
|
||||
lang, ext = os.path.splitext(filename)
|
||||
if abs_filename.endswith('.json'):
|
||||
translated[lang] = json.loads(open(abs_filename).read())
|
||||
translations[lang] = json.loads(open(abs_filename).read())
|
||||
|
||||
strings = translated[default]
|
||||
strings = translations[default]
|
||||
lc, enc = locale.getdefaultlocale()
|
||||
if lc:
|
||||
lang = lc[:2]
|
||||
if lang in translated:
|
||||
if lang in translations:
|
||||
# if a string doesn't exist, fallback to English
|
||||
for key in translated[default]:
|
||||
if key in translated[lang]:
|
||||
strings[key] = translated[lang][key]
|
||||
for key in translations[default]:
|
||||
if key in translations[lang]:
|
||||
strings[key] = translations[lang][key]
|
||||
|
||||
|
||||
def translated(k, gui=False):
|
||||
"""
|
||||
Returns a translated string.
|
||||
"""
|
||||
if gui:
|
||||
return strings[k].encode("utf-8").decode('utf-8', 'replace')
|
||||
else:
|
||||
|
@ -17,7 +17,7 @@ GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import Queue, mimetypes, platform, os, sys, zipfile, urllib2
|
||||
import Queue, mimetypes, platform, os, sys, urllib2
|
||||
from flask import Flask, Response, request, render_template_string, abort
|
||||
|
||||
import strings, helpers
|
||||
@ -70,10 +70,10 @@ REQUEST_CANCELED = 4
|
||||
q = Queue.Queue()
|
||||
|
||||
|
||||
def add_request(type, path, data=None):
|
||||
def add_request(request_type, path, data=None):
|
||||
global q
|
||||
q.put({
|
||||
'type': type,
|
||||
'type': request_type,
|
||||
'path': path,
|
||||
'data': data
|
||||
})
|
||||
@ -148,7 +148,7 @@ def download(slug_candidate):
|
||||
basename = os.path.basename(zip_filename)
|
||||
|
||||
def generate():
|
||||
chunk_size = 102400 # 100kb
|
||||
chunk_size = 102400 # 100kb
|
||||
|
||||
fp = open(zip_filename, 'rb')
|
||||
done = False
|
||||
|
@ -20,7 +20,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import os, sys, inspect, platform
|
||||
from onionshare import helpers
|
||||
|
||||
|
||||
def get_onionshare_gui_dir():
|
||||
"""
|
||||
Returns the OnionShare gui directory.
|
||||
"""
|
||||
p = helpers.get_platform()
|
||||
if p == 'Darwin':
|
||||
onionshare_gui_dir = os.path.dirname(__file__)
|
||||
@ -32,6 +36,9 @@ onionshare_gui_dir = get_onionshare_gui_dir()
|
||||
|
||||
|
||||
def get_image_path(filename):
|
||||
"""
|
||||
Returns the OnionShare image path.
|
||||
"""
|
||||
p = helpers.get_platform()
|
||||
if p == 'Linux' or p == 'Tails':
|
||||
prefix = os.path.join(sys.prefix, 'share/onionshare/images')
|
||||
|
@ -26,7 +26,7 @@ import common
|
||||
try:
|
||||
import onionshare
|
||||
except ImportError:
|
||||
sys.path.append(os.path.abspath(common.onionshare_gui_dir+"/.."))
|
||||
sys.path.append(os.path.abspath(common.onionshare_gui_dir + "/.."))
|
||||
import onionshare
|
||||
from onionshare import strings, helpers, web
|
||||
|
||||
@ -42,6 +42,14 @@ class Application(QtGui.QApplication):
|
||||
if platform == 'Linux':
|
||||
self.setAttribute(QtCore.Qt.AA_X11InitThreads, True)
|
||||
QtGui.QApplication.__init__(self, sys.argv)
|
||||
self.installEventFilter(self)
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
if (event.type() == QtCore.QEvent.KeyPress and
|
||||
event.key() == QtCore.Qt.Key_Q and
|
||||
event.modifiers() == QtCore.Qt.ControlModifier):
|
||||
self.quit()
|
||||
return False
|
||||
|
||||
|
||||
class OnionShareGui(QtGui.QWidget):
|
||||
|
@ -144,7 +144,7 @@ class ServerStatus(QtGui.QVBoxLayout):
|
||||
GMEM_DDESHARE = 0x2000
|
||||
ctypes.windll.user32.OpenClipboard(None)
|
||||
ctypes.windll.user32.EmptyClipboard()
|
||||
hcd = ctypes.windll.kernel32.GlobalAlloc(GMEM_DDESHARE, len(bytes(url))+1)
|
||||
hcd = ctypes.windll.kernel32.GlobalAlloc(GMEM_DDESHARE, len(bytes(url)) + 1)
|
||||
pch_data = ctypes.windll.kernel32.GlobalLock(hcd)
|
||||
ctypes.cdll.msvcrt.strcpy(ctypes.c_char_p(pch_data), bytes(url))
|
||||
ctypes.windll.kernel32.GlobalUnlock(hcd)
|
||||
|
Loading…
Reference in New Issue
Block a user