mirror of
https://github.com/onionshare/onionshare.git
synced 2024-10-01 01:35:40 -04:00
commit
d0bdb9143f
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
"""
|
||||
Check translation lacked or disused.
|
||||
|
||||
Example:
|
||||
@ -24,7 +24,7 @@ es disused gui_starting_server
|
||||
2. load translation key from locale/*.json.
|
||||
3. compare these.
|
||||
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
import fileinput, argparse, re, os, codecs, json, sys
|
||||
@ -75,13 +75,11 @@ def main():
|
||||
key = m.group(1)
|
||||
translate_keys.add(key)
|
||||
|
||||
|
||||
if args.show_all_keys:
|
||||
for k in sorted(translate_keys):
|
||||
print k
|
||||
sys.exit()
|
||||
|
||||
|
||||
locale_files = [f for f in files_in(dir, 'locale') if f.endswith('.json')]
|
||||
for locale_file in locale_files:
|
||||
with codecs.open(locale_file, 'r', encoding='utf-8') as f:
|
||||
|
@ -32,6 +32,7 @@ def get_platform():
|
||||
p = 'Tails'
|
||||
return p
|
||||
|
||||
|
||||
def get_onionshare_dir():
|
||||
if get_platform() == 'Darwin':
|
||||
onionshare_dir = os.path.dirname(__file__)
|
||||
@ -39,6 +40,7 @@ def get_onionshare_dir():
|
||||
onionshare_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||
return onionshare_dir
|
||||
|
||||
|
||||
def constant_time_compare(val1, val2):
|
||||
_builtin_constant_time_compare = getattr(hmac, 'compare_digest', None)
|
||||
if _builtin_constant_time_compare is not None:
|
||||
@ -55,6 +57,7 @@ def constant_time_compare(val1, val2):
|
||||
result |= x ^ y
|
||||
return result == 0
|
||||
|
||||
|
||||
def random_string(num_bytes, output_len=None):
|
||||
b = os.urandom(num_bytes)
|
||||
h = hashlib.sha256(b).digest()[:16]
|
||||
@ -63,6 +66,7 @@ def random_string(num_bytes, output_len=None):
|
||||
return s
|
||||
return s[:output_len]
|
||||
|
||||
|
||||
def human_readable_filesize(b):
|
||||
thresh = 1024.0
|
||||
if b < thresh:
|
||||
@ -75,9 +79,11 @@ def human_readable_filesize(b):
|
||||
u += 1
|
||||
return '{0} {1}'.format(round(b, 1), units[u])
|
||||
|
||||
|
||||
def is_root():
|
||||
return os.geteuid() == 0
|
||||
|
||||
|
||||
def dir_size(start_path):
|
||||
total_size = 0
|
||||
for dirpath, dirnames, filenames in os.walk(start_path):
|
||||
@ -87,6 +93,7 @@ def dir_size(start_path):
|
||||
total_size += os.path.getsize(fp)
|
||||
return total_size
|
||||
|
||||
|
||||
def get_tmp_dir():
|
||||
if get_platform() == "Windows":
|
||||
if 'Temp' in os.environ:
|
||||
@ -97,6 +104,7 @@ def get_tmp_dir():
|
||||
temp = '/tmp'
|
||||
return temp
|
||||
|
||||
|
||||
class ZipWriter(object):
|
||||
def __init__(self, zip_filename=None):
|
||||
if zip_filename:
|
||||
@ -120,4 +128,3 @@ class ZipWriter(object):
|
||||
|
||||
def close(self):
|
||||
self.z.close()
|
||||
|
||||
|
@ -25,11 +25,17 @@ from stem import SocketError
|
||||
|
||||
import strings, helpers, web
|
||||
|
||||
class NoTor(Exception): pass
|
||||
class TailsError(Exception): pass
|
||||
|
||||
class NoTor(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class TailsError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def hsdic2list(dic):
|
||||
"Convert what we get from get_conf_map to what we need for set_options"
|
||||
"""Convert what we get from get_conf_map to what we need for set_options"""
|
||||
return [
|
||||
pair for pairs in [
|
||||
[('HiddenServiceDir', vals[0]), ('HiddenServicePort', vals[1])]
|
||||
@ -37,6 +43,7 @@ def hsdic2list(dic):
|
||||
] for pair in pairs
|
||||
]
|
||||
|
||||
|
||||
class OnionShare(object):
|
||||
def __init__(self, debug=False, local_only=False, stay_open=False):
|
||||
self.port = None
|
||||
@ -56,7 +63,6 @@ class OnionShare(object):
|
||||
# files and dirs to delete on shutdown
|
||||
self.cleanup_filenames = []
|
||||
|
||||
|
||||
def cleanup(self):
|
||||
if self.controller:
|
||||
# Get fresh hidden services (maybe changed since last time)
|
||||
@ -191,6 +197,7 @@ class OnionShare(object):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def tails_root():
|
||||
# if running in Tails and as root, do only the things that require root
|
||||
if helpers.get_platform() == 'Tails' and helpers.is_root():
|
||||
@ -205,7 +212,8 @@ def tails_root():
|
||||
sys.exit(-1)
|
||||
|
||||
# open hole in firewall
|
||||
subprocess.call(['/sbin/iptables', '-I', 'OUTPUT', '-o', 'lo', '-p', 'tcp', '--dport', str(port), '-j', 'ACCEPT'])
|
||||
subprocess.call(['/sbin/iptables', '-I', 'OUTPUT', '-o', 'lo',
|
||||
'-p', 'tcp', '--dport', str(port), '-j', 'ACCEPT'])
|
||||
|
||||
# start hidden service
|
||||
app = OnionShare()
|
||||
@ -217,8 +225,10 @@ def tails_root():
|
||||
|
||||
# close hole in firewall on shutdown
|
||||
import signal
|
||||
|
||||
def handler(signum=None, frame=None):
|
||||
subprocess.call(['/sbin/iptables', '-D', 'OUTPUT', '-o', 'lo', '-p', 'tcp', '--dport', str(port), '-j', 'ACCEPT'])
|
||||
subprocess.call(['/sbin/iptables', '-D', 'OUTPUT', '-o', 'lo',
|
||||
'-p', 'tcp', '--dport', str(port), '-j', 'ACCEPT'])
|
||||
sys.exit()
|
||||
for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGHUP, signal.SIGQUIT]:
|
||||
signal.signal(sig, handler)
|
||||
@ -227,6 +237,7 @@ def tails_root():
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def main():
|
||||
strings.load_strings()
|
||||
tails_root()
|
||||
|
@ -65,6 +65,7 @@ PRINTABLE_PROXY_TYPES = {SOCKS4: "SOCKS4", SOCKS5: "SOCKS5", HTTP: "HTTP"}
|
||||
|
||||
_orgsocket = _orig_socket = socket.socket
|
||||
|
||||
|
||||
class ProxyError(IOError):
|
||||
"""
|
||||
socket_err contains original socket.error exception.
|
||||
@ -79,33 +80,55 @@ class ProxyError(IOError):
|
||||
def __str__(self):
|
||||
return self.msg
|
||||
|
||||
class GeneralProxyError(ProxyError): pass
|
||||
class ProxyConnectionError(ProxyError): pass
|
||||
class SOCKS5AuthError(ProxyError): pass
|
||||
class SOCKS5Error(ProxyError): pass
|
||||
class SOCKS4Error(ProxyError): pass
|
||||
class HTTPError(ProxyError): pass
|
||||
|
||||
SOCKS4_ERRORS = { 0x5B: "Request rejected or failed",
|
||||
class GeneralProxyError(ProxyError):
|
||||
pass
|
||||
|
||||
|
||||
class ProxyConnectionError(ProxyError):
|
||||
pass
|
||||
|
||||
|
||||
class SOCKS5AuthError(ProxyError):
|
||||
pass
|
||||
|
||||
|
||||
class SOCKS5Error(ProxyError):
|
||||
pass
|
||||
|
||||
|
||||
class SOCKS4Error(ProxyError):
|
||||
pass
|
||||
|
||||
|
||||
class HTTPError(ProxyError):
|
||||
pass
|
||||
|
||||
|
||||
SOCKS4_ERRORS = {
|
||||
0x5B: "Request rejected or failed",
|
||||
0x5C: "Request rejected because SOCKS server cannot connect to identd on the client",
|
||||
0x5D: "Request rejected because the client program and identd report different user-ids"
|
||||
0x5D: "Request rejected because the client program and identd report different user-ids",
|
||||
}
|
||||
|
||||
SOCKS5_ERRORS = { 0x01: "General SOCKS server failure",
|
||||
SOCKS5_ERRORS = {
|
||||
0x01: "General SOCKS server failure",
|
||||
0x02: "Connection not allowed by ruleset",
|
||||
0x03: "Network unreachable",
|
||||
0x04: "Host unreachable",
|
||||
0x05: "Connection refused",
|
||||
0x06: "TTL expired",
|
||||
0x07: "Command not supported, or protocol error",
|
||||
0x08: "Address type not supported"
|
||||
0x08: "Address type not supported",
|
||||
}
|
||||
|
||||
DEFAULT_PORTS = { SOCKS4: 1080,
|
||||
DEFAULT_PORTS = {
|
||||
SOCKS4: 1080,
|
||||
SOCKS5: 1080,
|
||||
HTTP: 8080
|
||||
HTTP: 8080,
|
||||
}
|
||||
|
||||
|
||||
def set_default_proxy(proxy_type=None, addr=None, port=None, rdns=True, username=None, password=None):
|
||||
"""
|
||||
set_default_proxy(proxy_type, addr[, port[, rdns[, username, password]]])
|
||||
@ -119,6 +142,7 @@ def set_default_proxy(proxy_type=None, addr=None, port=None, rdns=True, username
|
||||
|
||||
setdefaultproxy = set_default_proxy
|
||||
|
||||
|
||||
def get_default_proxy():
|
||||
"""
|
||||
Returns the default proxy, set by set_default_proxy.
|
||||
@ -127,6 +151,7 @@ def get_default_proxy():
|
||||
|
||||
getdefaultproxy = get_default_proxy
|
||||
|
||||
|
||||
def wrap_module(module):
|
||||
"""
|
||||
Attempts to replace a module's socket library with a SOCKS socket. Must set
|
||||
@ -141,6 +166,7 @@ def wrap_module(module):
|
||||
|
||||
wrapmodule = wrap_module
|
||||
|
||||
|
||||
def create_connection(dest_pair, proxy_type=None, proxy_addr=None,
|
||||
proxy_port=None, proxy_username=None,
|
||||
proxy_password=None, timeout=None):
|
||||
@ -161,6 +187,7 @@ def create_connection(dest_pair, proxy_type=None, proxy_addr=None,
|
||||
sock.connect(dest_pair)
|
||||
return sock
|
||||
|
||||
|
||||
class socksocket(socket.socket):
|
||||
"""socksocket([family[, type[, proto]]]) -> socket object
|
||||
|
||||
@ -181,9 +208,10 @@ class socksocket(socket.socket):
|
||||
self.proxy_sockname = None
|
||||
self.proxy_peername = None
|
||||
|
||||
self.proxy_negotiators = { SOCKS4: self._negotiate_SOCKS4,
|
||||
self.proxy_negotiators = {
|
||||
SOCKS4: self._negotiate_SOCKS4,
|
||||
SOCKS5: self._negotiate_SOCKS5,
|
||||
HTTP: self._negotiate_HTTP
|
||||
HTTP: self._negotiate_HTTP,
|
||||
}
|
||||
|
||||
def _recvall(self, count):
|
||||
@ -446,7 +474,6 @@ class socksocket(socket.socket):
|
||||
self.proxy_sockname = (b"0.0.0.0", 0)
|
||||
self.proxy_peername = addr, dest_port
|
||||
|
||||
|
||||
def connect(self, dest_pair):
|
||||
"""
|
||||
Connects to the specified destination through a proxy.
|
||||
@ -465,7 +492,6 @@ class socksocket(socket.socket):
|
||||
or not isinstance(dest_port, int)):
|
||||
raise GeneralProxyError("Invalid destination-connection (host, port) pair")
|
||||
|
||||
|
||||
if proxy_type is None:
|
||||
# Treat like regular socket object
|
||||
_orig_socket.connect(self, (dest_addr, dest_port))
|
||||
|
@ -22,6 +22,7 @@ import helpers
|
||||
|
||||
strings = {}
|
||||
|
||||
|
||||
def load_strings(default="en"):
|
||||
global strings
|
||||
|
||||
@ -49,6 +50,7 @@ def load_strings(default="en"):
|
||||
if key in translated[lang]:
|
||||
strings[key] = translated[lang][key]
|
||||
|
||||
|
||||
def translated(k, gui=False):
|
||||
if gui:
|
||||
return strings[k].encode("utf-8").decode('utf-8', 'replace')
|
||||
|
@ -28,6 +28,8 @@ app = Flask(__name__)
|
||||
file_info = []
|
||||
zip_filename = None
|
||||
zip_filesize = None
|
||||
|
||||
|
||||
def set_file_info(filenames):
|
||||
global file_info, zip_filename, zip_filesize
|
||||
|
||||
@ -59,6 +61,7 @@ def set_file_info(filenames):
|
||||
zip_filename = z.zip_filename
|
||||
zip_filesize = os.path.getsize(zip_filename)
|
||||
|
||||
|
||||
REQUEST_LOAD = 0
|
||||
REQUEST_DOWNLOAD = 1
|
||||
REQUEST_PROGRESS = 2
|
||||
@ -66,6 +69,7 @@ REQUEST_OTHER = 3
|
||||
REQUEST_CANCELED = 4
|
||||
q = Queue.Queue()
|
||||
|
||||
|
||||
def add_request(type, path, data=None):
|
||||
global q
|
||||
q.put({
|
||||
@ -74,16 +78,22 @@ def add_request(type, path, data=None):
|
||||
'data': data
|
||||
})
|
||||
|
||||
|
||||
slug = helpers.random_string(16)
|
||||
download_count = 0
|
||||
|
||||
stay_open = False
|
||||
|
||||
|
||||
def set_stay_open(new_stay_open):
|
||||
global stay_open
|
||||
stay_open = new_stay_open
|
||||
|
||||
|
||||
def get_stay_open():
|
||||
return stay_open
|
||||
|
||||
|
||||
def debug_mode():
|
||||
import logging
|
||||
|
||||
@ -96,6 +106,7 @@ def debug_mode():
|
||||
log_handler.setLevel(logging.WARNING)
|
||||
app.logger.addHandler(log_handler)
|
||||
|
||||
|
||||
@app.route("/<slug_candidate>")
|
||||
def index(slug_candidate):
|
||||
if not helpers.constant_time_compare(slug.encode('ascii'), slug_candidate.encode('ascii')):
|
||||
@ -112,6 +123,7 @@ def index(slug_candidate):
|
||||
strings=strings.strings
|
||||
)
|
||||
|
||||
|
||||
@app.route("/<slug_candidate>/download")
|
||||
def download(slug_candidate):
|
||||
global download_count
|
||||
@ -150,7 +162,8 @@ def download(slug_candidate):
|
||||
# tell GUI the progress
|
||||
downloaded_bytes = fp.tell()
|
||||
percent = round((1.0 * downloaded_bytes / zip_filesize) * 100, 2)
|
||||
sys.stdout.write("\r{0}, {1}% ".format(helpers.human_readable_filesize(downloaded_bytes), percent))
|
||||
sys.stdout.write(
|
||||
"\r{0}, {1}% ".format(helpers.human_readable_filesize(downloaded_bytes), percent))
|
||||
sys.stdout.flush()
|
||||
add_request(REQUEST_PROGRESS, path, {'id': download_id, 'bytes': downloaded_bytes})
|
||||
except:
|
||||
@ -181,6 +194,7 @@ def download(slug_candidate):
|
||||
r.headers.add('Content-Type', content_type)
|
||||
return r
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
add_request(REQUEST_OTHER, request.path)
|
||||
@ -188,6 +202,8 @@ def page_not_found(e):
|
||||
|
||||
# shutting down the server only works within the context of flask, so the easiest way to do it is over http
|
||||
shutdown_slug = helpers.random_string(16)
|
||||
|
||||
|
||||
@app.route("/<shutdown_slug_candidate>/shutdown")
|
||||
def shutdown(shutdown_slug_candidate):
|
||||
if not helpers.constant_time_compare(shutdown_slug.encode('ascii'), shutdown_slug_candidate.encode('ascii')):
|
||||
@ -201,16 +217,19 @@ def shutdown(shutdown_slug_candidate):
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
def start(port, stay_open=False):
|
||||
set_stay_open(stay_open)
|
||||
app.run(port=port, threaded=True)
|
||||
|
||||
|
||||
def stop(port):
|
||||
# to stop flask, load http://127.0.0.1:<port>/<shutdown_slug>/shutdown
|
||||
if helpers.get_platform() == 'Tails':
|
||||
# in Tails everything is proxies over Tor, so we need to get lower level
|
||||
# to connect not over the proxy
|
||||
import socket
|
||||
|
||||
s = socket.socket()
|
||||
s.connect(('127.0.0.1', port))
|
||||
s.sendall('GET /{0}/shutdown HTTP/1.1\r\n\r\n'.format(shutdown_slug))
|
||||
|
@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import os, sys, inspect, platform
|
||||
|
||||
|
||||
def get_onionshare_gui_dir():
|
||||
if platform.system() == 'Darwin':
|
||||
onionshare_gui_dir = os.path.dirname(__file__)
|
||||
@ -28,6 +29,7 @@ def get_onionshare_gui_dir():
|
||||
|
||||
onionshare_gui_dir = get_onionshare_gui_dir()
|
||||
|
||||
|
||||
def get_image_path(filename):
|
||||
if platform.system() == 'Linux':
|
||||
prefix = os.path.join(sys.prefix, 'share/onionshare/images')
|
||||
|
@ -22,6 +22,7 @@ from PyQt4 import QtCore, QtGui
|
||||
import common
|
||||
from onionshare import strings, helpers
|
||||
|
||||
|
||||
class Downloads(QtGui.QVBoxLayout):
|
||||
def __init__(self):
|
||||
super(Downloads, self).__init__()
|
||||
|
@ -23,6 +23,7 @@ from PyQt4 import QtCore, QtGui
|
||||
import common
|
||||
from onionshare import strings, helpers
|
||||
|
||||
|
||||
class FileList(QtGui.QListWidget):
|
||||
files_dropped = QtCore.pyqtSignal()
|
||||
files_updated = QtCore.pyqtSignal()
|
||||
@ -137,6 +138,7 @@ class FileList(QtGui.QListWidget):
|
||||
u += 1
|
||||
return '{0} {1}'.format(round(b, 1), units[u])
|
||||
|
||||
|
||||
class FileSelection(QtGui.QVBoxLayout):
|
||||
def __init__(self):
|
||||
super(FileSelection, self).__init__()
|
||||
@ -186,14 +188,16 @@ class FileSelection(QtGui.QVBoxLayout):
|
||||
self.file_list.update()
|
||||
|
||||
def add_files(self):
|
||||
filenames = QtGui.QFileDialog.getOpenFileNames(caption=strings._('gui_choose_files', True), options=QtGui.QFileDialog.ReadOnly)
|
||||
filenames = QtGui.QFileDialog.getOpenFileNames(
|
||||
caption=strings._('gui_choose_files', True), options=QtGui.QFileDialog.ReadOnly)
|
||||
if filenames:
|
||||
for filename in filenames:
|
||||
self.file_list.add_file(str(filename))
|
||||
self.update()
|
||||
|
||||
def add_dir(self):
|
||||
filename = QtGui.QFileDialog.getExistingDirectory(caption=strings._('gui_choose_folder', True), options=QtGui.QFileDialog.ReadOnly)
|
||||
filename = QtGui.QFileDialog.getExistingDirectory(
|
||||
caption=strings._('gui_choose_folder', True), options=QtGui.QFileDialog.ReadOnly)
|
||||
if filename:
|
||||
self.file_list.add_file(str(filename))
|
||||
self.update()
|
||||
|
@ -35,6 +35,7 @@ from server_status import ServerStatus
|
||||
from downloads import Downloads
|
||||
from options import Options
|
||||
|
||||
|
||||
class Application(QtGui.QApplication):
|
||||
def __init__(self):
|
||||
platform = helpers.get_platform()
|
||||
@ -42,6 +43,7 @@ class Application(QtGui.QApplication):
|
||||
self.setAttribute(QtCore.Qt.AA_X11InitThreads, True)
|
||||
QtGui.QApplication.__init__(self, sys.argv)
|
||||
|
||||
|
||||
class OnionShareGui(QtGui.QWidget):
|
||||
start_server_finished = QtCore.pyqtSignal()
|
||||
stop_server_finished = QtCore.pyqtSignal()
|
||||
@ -206,6 +208,7 @@ class OnionShareGui(QtGui.QWidget):
|
||||
def clear_message(self):
|
||||
self.status_bar.clearMessage()
|
||||
|
||||
|
||||
def alert(msg, icon=QtGui.QMessageBox.NoIcon):
|
||||
dialog = QtGui.QMessageBox()
|
||||
dialog.setWindowTitle("OnionShare")
|
||||
@ -214,6 +217,7 @@ def alert(msg, icon=QtGui.QMessageBox.NoIcon):
|
||||
dialog.setIcon(icon)
|
||||
dialog.exec_()
|
||||
|
||||
|
||||
def main():
|
||||
strings.load_strings()
|
||||
|
||||
|
@ -22,6 +22,7 @@ from PyQt4 import QtCore, QtGui
|
||||
import common
|
||||
from onionshare import strings, helpers
|
||||
|
||||
|
||||
class Options(QtGui.QHBoxLayout):
|
||||
def __init__(self, web):
|
||||
super(Options, self).__init__()
|
||||
|
@ -23,6 +23,7 @@ from PyQt4 import QtCore, QtGui
|
||||
import common
|
||||
from onionshare import strings, helpers
|
||||
|
||||
|
||||
class ServerStatus(QtGui.QVBoxLayout):
|
||||
server_started = QtCore.pyqtSignal()
|
||||
server_stopped = QtCore.pyqtSignal()
|
||||
|
17
setup.py
17
setup.py
@ -27,6 +27,7 @@ try:
|
||||
except ImportError:
|
||||
from distutils.core import setup
|
||||
|
||||
|
||||
def file_list(path):
|
||||
files = []
|
||||
for filename in os.listdir(path):
|
||||
@ -37,11 +38,23 @@ def file_list(path):
|
||||
|
||||
version = open('version').read().strip()
|
||||
|
||||
description = (
|
||||
"""OnionShare lets you securely and anonymously share a file of any size with someone. """
|
||||
"""It works by starting a web server, making it accessible as a Tor hidden service, """
|
||||
"""and generating an unguessable URL to access and download the file.""")
|
||||
|
||||
long_description = description + " " + (
|
||||
"""It doesn't require setting up a server on the internet somewhere or using a third """
|
||||
"""party filesharing service. You host the file on your own computer and use a Tor """
|
||||
"""hidden service to make it temporarily accessible over the internet. The other user """
|
||||
"""just needs to use Tor Browser to download the file from you."""
|
||||
)
|
||||
|
||||
setup(
|
||||
name='onionshare',
|
||||
version=version,
|
||||
description='OnionShare lets you securely and anonymously share a file of any size with someone. It works by starting a web server, making it accessible as a Tor hidden service, and generating an unguessable URL to access and download the file.',
|
||||
long_description="""OnionShare lets you securely and anonymously share a file of any size with someone. It works by starting a web server, making it accessible as a Tor hidden service, and generating an unguessable URL to access and download the file. It doesn't require setting up a server on the internet somewhere or using a third party filesharing service. You host the file on your own computer and use a Tor hidden service to make it temporarily accessible over the internet. The other user just needs to use Tor Browser to download the file from you.""",
|
||||
description=description,
|
||||
long_description=long_description,
|
||||
author='Micah Lee',
|
||||
author_email='micah@micahflee.com',
|
||||
url='https://github.com/micahflee/onionshare',
|
||||
|
@ -18,7 +18,9 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import division
|
||||
import os, sys, subprocess, time, hashlib, platform, json, locale, socket, argparse, Queue, inspect, base64, random, functools, logging, ctypes, hmac, shutil
|
||||
import os, sys, subprocess, time, hashlib, platform, json, locale, socket
|
||||
import argparse, Queue, inspect, base64, random, functools, logging, ctypes
|
||||
import hmac, shutil
|
||||
from itertools import izip
|
||||
import stem, stem.control, flask
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
@ -21,13 +21,15 @@ from nose import with_setup
|
||||
|
||||
import test_helpers
|
||||
|
||||
|
||||
def test_get_platform_on_tails():
|
||||
"get_platform() returns 'Tails' when hostname is 'amnesia'"
|
||||
helpers.platform.uname = lambda: ('Linux', 'amnesia', '3.14-1-amd64', '#1 SMP Debian 3.14.4-1 (2014-05-13)', 'x86_64', '')
|
||||
"""get_platform() returns 'Tails' when hostname is 'amnesia'"""
|
||||
helpers.platform.uname = lambda: ('Linux', 'amnesia', '3.14-1-amd64',
|
||||
'#1 SMP Debian 3.14.4-1 (2014-05-13)', 'x86_64', '')
|
||||
assert helpers.get_platform() == 'Tails'
|
||||
|
||||
|
||||
def test_get_platform_returns_platform_system():
|
||||
"get_platform() returns platform.system() when ONIONSHARE_PLATFORM is not defined"
|
||||
"""get_platform() returns platform.system() when ONIONSHARE_PLATFORM is not defined"""
|
||||
helpers.platform.system = lambda: 'Sega Saturn'
|
||||
assert helpers.get_platform() == 'Sega Saturn'
|
||||
|
||||
|
@ -21,19 +21,21 @@ import locale
|
||||
from onionshare import strings
|
||||
from nose import with_setup
|
||||
|
||||
|
||||
def test_starts_with_empty_strings():
|
||||
"creates an empty strings dict by default"
|
||||
"""creates an empty strings dict by default"""
|
||||
assert strings.strings == {}
|
||||
|
||||
|
||||
def test_load_strings_defaults_to_english():
|
||||
"load_strings() loads English by default"
|
||||
"""load_strings() loads English by default"""
|
||||
locale.getdefaultlocale = lambda: ('en_US', 'UTF-8')
|
||||
strings.load_strings()
|
||||
assert strings._('wait_for_hs') == "Waiting for HS to be ready:"
|
||||
|
||||
|
||||
def test_load_strings_loads_other_languages():
|
||||
"load_strings() loads other languages in different locales"
|
||||
"""load_strings() loads other languages in different locales"""
|
||||
locale.getdefaultlocale = lambda: ('fr_FR', 'UTF-8')
|
||||
strings.load_strings("fr")
|
||||
assert strings._('wait_for_hs') == "En attente du HS:"
|
||||
|
||||
|
@ -20,14 +20,16 @@ import socket
|
||||
from onionshare import OnionShare
|
||||
from nose import with_setup
|
||||
|
||||
|
||||
def test_choose_port_returns_a_port_number():
|
||||
"choose_port() returns a port number"
|
||||
"""choose_port() returns a port number"""
|
||||
app = OnionShare()
|
||||
app.choose_port()
|
||||
assert 1024 <= app.port <= 65535
|
||||
|
||||
|
||||
def test_choose_port_returns_an_open_port():
|
||||
"choose_port() returns an open port"
|
||||
"""choose_port() returns an open port"""
|
||||
app = OnionShare()
|
||||
# choose a new port
|
||||
app.choose_port()
|
||||
|
@ -19,17 +19,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from onionshare import web
|
||||
from nose import with_setup
|
||||
|
||||
|
||||
def test_generate_slug_length():
|
||||
"generates a 26-character slug"
|
||||
"""generates a 26-character slug"""
|
||||
assert len(web.slug) == 26
|
||||
|
||||
|
||||
def test_generate_slug_characters():
|
||||
"generates a base32-encoded slug"
|
||||
"""generates a base32-encoded slug"""
|
||||
|
||||
def is_b32(string):
|
||||
b32_alphabet = "01234556789abcdefghijklmnopqrstuvwxyz"
|
||||
return all(char in b32_alphabet for char in string)
|
||||
|
||||
assert is_b32(web.slug)
|
||||
|
||||
|
||||
|
@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import tempfile
|
||||
|
||||
|
||||
class MockSubprocess():
|
||||
def __init__(self):
|
||||
self.last_call = None
|
||||
@ -28,6 +29,7 @@ class MockSubprocess():
|
||||
def last_call_args(self):
|
||||
return self.last_call
|
||||
|
||||
|
||||
def write_tempfile(text):
|
||||
tempdir = tempfile.mkdtemp()
|
||||
path = tempdir + "/test-file.txt"
|
||||
@ -35,5 +37,3 @@ def write_tempfile(text):
|
||||
f.write(text)
|
||||
f.close()
|
||||
return path
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user