Adds local-only command line flag.

This commit is contained in:
Joshua Thayer 2014-06-05 16:11:21 -07:00
parent 5b03b41bcd
commit d0b3145e17

View file

@ -1,4 +1,4 @@
import os, sys, subprocess, time, hashlib, platform, json, locale, socket, re, argparse import os, sys, subprocess, time, hashlib, platform, json, locale, socket, argparse
from random import randint from random import randint
from functools import wraps from functools import wraps
@ -8,14 +8,20 @@ def get_platform():
else: else:
return platform.system() return platform.system()
if get_platform() == 'Tails': def append_lib_on_tails():
if get_platform() == 'Tails':
sys.path.append(os.path.dirname(__file__)+'/../tails/lib') sys.path.append(os.path.dirname(__file__)+'/../tails/lib')
append_lib_on_tails()
from stem.control import Controller from stem.control import Controller
from stem import SocketError from stem import SocketError
from flask import Flask, Markup, Response, request, make_response, send_from_directory, render_template_string from flask import Flask, Markup, Response, request, make_response, send_from_directory, render_template_string
class NoTor(Exception):
pass
app = Flask(__name__) app = Flask(__name__)
strings = {} strings = {}
@ -23,61 +29,26 @@ strings = {}
# generate an unguessable string # generate an unguessable string
slug = os.urandom(16).encode('hex') slug = os.urandom(16).encode('hex')
# file information # information about the file
filename = filehash = filesize = '' filename = filesize = filehash = None
def set_file_info(new_filename, new_filehash, new_filesize):
@app.after_request global filename, filehash, filesize
def after_request(response): filename = new_filename
response.headers.add('Accept-Ranges', 'bytes') filehash = new_filehash
return response filesize = new_filesize
def send_file_partial(range_header):
global filename
dirname = os.path.dirname(filename)
basename = os.path.basename(filename)
size = os.path.getsize(filename)
byte1, byte2 = 0, None
m = re.search('(\d+)-(\d*)', range_header)
g = m.groups()
if g[0]: byte1 = int(g[0])
if g[1]: byte2 = int(g[1])
length = size - byte1
if byte2 is not None:
length = (byte2 - byte1) + 1
data = None
with open(filename, 'rb') as f:
f.seek(byte1)
data = f.read(length)
rv = Response(data,
206,
# mimetype=mimetypes.guess_type(path)[0],
direct_passthrough=True)
rv.headers.add('Content-Range', 'bytes {0}-{1}/{2}'.format(byte1, byte1 + length - 1, size))
return rv
@app.route("/{0}".format(slug)) @app.route("/{0}".format(slug))
def index(): def index():
global filename, filesize, filehash, slug, strings global filename, filesize, filehash, slug, strings
print 'filename: {0}'.format(filename)
print 'filehash: {0}'.format(filehash)
print 'filesize: {0}'.format(filesize)
return render_template_string(open('{0}/index.html'.format(os.path.dirname(__file__))).read(), return render_template_string(open('{0}/index.html'.format(os.path.dirname(__file__))).read(),
slug=slug, filename=os.path.basename(filename), filehash=filehash, filesize=filesize, strings=strings) slug=slug, filename=os.path.basename(filename), filehash=filehash, filesize=filesize, strings=strings)
@app.route("/{0}/download".format(slug)) @app.route("/{0}/download".format(slug))
def download(): def download():
global filename global filename
range_header = request.headers.get('Range', None)
if range_header:
return send_file_partial(range_header)
dirname = os.path.dirname(filename) dirname = os.path.dirname(filename)
basename = os.path.basename(filename) basename = os.path.basename(filename)
return send_from_directory(dirname, basename, as_attachment=True) return send_from_directory(dirname, basename, as_attachment=True)
@ -120,24 +91,10 @@ def load_strings(default="en"):
lang = lc[:2] lang = lc[:2]
if lang in translated: if lang in translated:
strings = translated[lang] strings = translated[lang]
return strings
def main(): def file_crunching(filename):
global filename, filehash, filesize
load_strings()
parser = argparse.ArgumentParser()
parser.add_argument('--local-only', action='store_true', dest='local_only', help='Do not attempt to use tor: for development only')
parser.add_argument('filename', nargs=1)
args = parser.parse_args()
filename = os.path.abspath(args.filename[0])
local_only = args.local_only
if not (filename and os.path.isfile(filename)):
sys.exit(strings["not_a_file"].format(filename))
# calculate filehash, file size # calculate filehash, file size
print strings["calculating_sha1"]
BLOCKSIZE = 65536 BLOCKSIZE = 65536
hasher = hashlib.sha1() hasher = hashlib.sha1()
with open(filename, 'rb') as f: with open(filename, 'rb') as f:
@ -147,44 +104,72 @@ def main():
buf = f.read(BLOCKSIZE) buf = f.read(BLOCKSIZE)
filehash = hasher.hexdigest() filehash = hasher.hexdigest()
filesize = os.path.getsize(filename) filesize = os.path.getsize(filename)
return filehash, filesize
def choose_port():
# let the OS choose a port # let the OS choose a port
tmpsock = socket.socket() tmpsock = socket.socket()
tmpsock.bind(("127.0.0.1", 0)) tmpsock.bind(("127.0.0.1", 0))
port = tmpsock.getsockname()[1] port = tmpsock.getsockname()[1]
tmpsock.close() tmpsock.close()
return port
def start_hidden_service(port):
# connect to the tor controlport
controlports = [9051, 9151]
controller = False
for controlport in controlports:
try:
controller = Controller.from_port(port=controlport)
except SocketError:
pass
if not controller:
raise NoTor(strings["cant_connect_ctrlport"].format(controlports))
controller.authenticate()
# set up hidden service
controller.set_options([
('HiddenServiceDir', get_hidden_service_dir(port)),
('HiddenServicePort', '80 127.0.0.1:{0}'.format(port))
])
onion_host = get_hidden_service_hostname(port)
return onion_host
def main():
load_strings()
parser = argparse.ArgumentParser()
parser.add_argument('--local-only', action='store_true', dest='local_only', help='Do not attempt to use tor: for development only')
parser.add_argument('filename', nargs=1)
args = parser.parse_args()
filename = os.path.abspath(args.filename[0])
local_only = args.local_only
if not (filename and os.path.isfile(filename)):
sys.exit(strings["not_a_file"].format(filename))
filename = os.path.abspath(filename)
port = choose_port()
local_host = "127.0.0.1:{0}".format(port) local_host = "127.0.0.1:{0}".format(port)
if not local_only: if not local_only:
# connect to the tor controlport # try starting hidden service
print strings["connecting_ctrlport"].format(port) print strings["connecting_ctrlport"].format(port)
controlports = [9051, 9151] try:
controller = False onion_host = start_hidden_service(port)
except NoTor as e:
for controlport in controlports: sys.exit(e.args[0])
try:
if not controller:
controller = Controller.from_port(port=controlport)
except SocketError:
pass
if not controller:
sys.exit(strings["cant_connect_ctrlport"].format(controlports))
controller.authenticate()
# set up hidden service # startup
controller.set_options([ print strings["calculating_sha1"]
('HiddenServiceDir', get_hidden_service_dir(port)), filehash, filesize = file_crunching(filename)
('HiddenServicePort', '80 127.0.0.1:{0}'.format(port)) set_file_info(filename, filehash, filesize)
]) tails_open_port(port)
onion_host = get_hidden_service_hostname(port)
# punch a hole in the firewall
tails_open_port(port)
# instructions
print '\n' + strings["give_this_url"] print '\n' + strings["give_this_url"]
if local_only: if local_only:
print 'http://{0}/{1}'.format(local_host, slug) print 'http://{0}/{1}'.format(local_host, slug)
@ -192,13 +177,13 @@ def main():
print 'http://{0}/{1}'.format(onion_host, slug) print 'http://{0}/{1}'.format(onion_host, slug)
print '' print ''
print strings["ctrlc_to_stop"] print strings["ctrlc_to_stop"]
# start the web server # start the web server
app.run(port=port, debug=True) app.run(port=port)
print '\n' print '\n'
# shutdown # shutdown
tails_close_port(port) tails_close_port(port)
if __name__ == '__main__': if __name__ == '__main__':
main() main()