2014-05-20 15:44:00 -04:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
2014-05-22 15:26:08 -04:00
|
|
|
import os, sys, subprocess, time, hashlib, platform
|
2014-05-20 15:44:00 -04:00
|
|
|
from random import randint
|
|
|
|
from functools import wraps
|
2014-05-20 19:02:33 -04:00
|
|
|
|
2014-05-22 15:26:08 -04:00
|
|
|
sys.path.append(os.path.dirname(__file__)+'/lib')
|
2014-05-20 19:02:33 -04:00
|
|
|
|
2014-05-21 14:23:37 -04:00
|
|
|
from stem.control import Controller
|
|
|
|
from stem import SocketError
|
|
|
|
|
2014-05-20 16:57:39 -04:00
|
|
|
from flask import Flask, Markup, Response, request, make_response, send_from_directory
|
2014-05-20 15:44:00 -04:00
|
|
|
app = Flask(__name__)
|
|
|
|
|
2014-05-21 21:17:14 -04:00
|
|
|
# generate an unguessable string
|
|
|
|
slug = os.urandom(16).encode('hex')
|
|
|
|
|
|
|
|
# file information
|
|
|
|
filename = filehash = filesize = ''
|
|
|
|
|
|
|
|
@app.route("/{0}".format(slug))
|
2014-05-20 16:57:39 -04:00
|
|
|
def index():
|
2014-05-21 21:17:14 -04:00
|
|
|
global filename, filesize, filehash, slug
|
|
|
|
return "<html><head><title>OnionShare</title><style>body {{ background-color: #222222; color: #ffffff; text-align: center; font-family: arial; padding: 5em; }} a {{ color: #ffee00; text-decoration: none; }} a:hover{{ text-decoration: underline; }}</style></head><body><h1><a href='/{0}/download'>{1}</a></h1><p>SHA1 checksum: <strong>{2}</strong><br/>File size: <strong>{3} bytes</strong></p></body></html>".format(slug, os.path.basename(filename), filehash, filesize)
|
2014-05-20 16:57:39 -04:00
|
|
|
|
2014-05-21 21:17:14 -04:00
|
|
|
@app.route("/{0}/download".format(slug))
|
2014-05-20 16:57:39 -04:00
|
|
|
def download():
|
|
|
|
global filename
|
|
|
|
dirname = os.path.dirname(filename)
|
|
|
|
basename = os.path.basename(filename)
|
|
|
|
return send_from_directory(dirname, basename, as_attachment=True)
|
2014-05-20 15:44:00 -04:00
|
|
|
|
2014-05-21 14:56:09 -04:00
|
|
|
def get_platform():
|
|
|
|
if 'ONIONSHARE_PLATFORM' in os.environ:
|
|
|
|
return os.environ['ONIONSHARE_PLATFORM']
|
|
|
|
else:
|
2014-05-22 14:23:22 -04:00
|
|
|
return platform.system()
|
|
|
|
|
|
|
|
def get_hidden_service_dir(port):
|
|
|
|
if get_platform() == "Windows":
|
|
|
|
if 'Temp' in os.environ:
|
|
|
|
temp = os.environ['Temp'].replace('\\', '/')
|
|
|
|
else:
|
|
|
|
temp = 'C:/tmp'
|
|
|
|
return "{0}/onionshare_hidden_service_{1}".format(temp, port)
|
2014-05-22 15:26:08 -04:00
|
|
|
|
2014-05-22 14:23:22 -04:00
|
|
|
return "/tmp/onionshare_hidden_service_{0}".format(port)
|
|
|
|
|
|
|
|
def get_hidden_service_hostname(port):
|
|
|
|
hostname_file = '{0}/hostname'.format(get_hidden_service_dir(port))
|
|
|
|
return open(hostname_file, 'r').read().strip()
|
2014-05-21 14:56:09 -04:00
|
|
|
|
2014-05-21 14:51:04 -04:00
|
|
|
def tails_open_port(port):
|
2014-05-21 14:56:09 -04:00
|
|
|
if get_platform() == 'Tails':
|
2014-05-21 14:51:04 -04:00
|
|
|
print 'Punching a hole in the firewall'
|
|
|
|
subprocess.call(['/sbin/iptables', '-I', 'OUTPUT', '-o', 'lo', '-p', 'tcp', '--dport', str(port), '-j', 'ACCEPT'])
|
2014-05-20 15:44:00 -04:00
|
|
|
|
2014-05-21 14:51:04 -04:00
|
|
|
def tails_close_port(port):
|
2014-05-21 14:56:09 -04:00
|
|
|
if get_platform() == 'Tails':
|
2014-05-21 14:51:04 -04:00
|
|
|
print 'Closing hole in firewall'
|
|
|
|
subprocess.call(['/sbin/iptables', '-I', 'OUTPUT', '-o', 'lo', '-p', 'tcp', '--dport', str(port), '-j', 'REJECT'])
|
2014-05-20 15:44:00 -04:00
|
|
|
|
2014-05-21 14:51:04 -04:00
|
|
|
if __name__ == '__main__':
|
2014-05-20 16:57:39 -04:00
|
|
|
# validate filename
|
2014-05-20 15:44:00 -04:00
|
|
|
if len(sys.argv) != 2:
|
|
|
|
sys.exit('Usage: {0} [filename]'.format(sys.argv[0]));
|
|
|
|
filename = sys.argv[1]
|
|
|
|
if not os.path.isfile(filename):
|
|
|
|
sys.exit('{0} is not a file'.format(filename))
|
|
|
|
|
2014-05-20 16:57:39 -04:00
|
|
|
# calculate filehash, file size
|
|
|
|
sha1 = hashlib.sha1()
|
|
|
|
f = open(filename, 'rb')
|
|
|
|
try:
|
|
|
|
sha1.update(f.read())
|
|
|
|
finally:
|
|
|
|
f.close()
|
|
|
|
filehash = sha1.hexdigest()
|
|
|
|
filesize = os.path.getsize(filename)
|
|
|
|
|
2014-05-21 21:17:14 -04:00
|
|
|
# choose a port
|
2014-05-20 15:44:00 -04:00
|
|
|
port = randint(1025, 65535)
|
|
|
|
|
2014-05-21 14:23:37 -04:00
|
|
|
# connect to the tor controlport
|
|
|
|
print 'Connecting to Tor ControlPort to set up hidden service on port {0}'.format(port)
|
|
|
|
controlports = [9051, 9151]
|
|
|
|
controller = False
|
|
|
|
for controlport in controlports:
|
|
|
|
try:
|
|
|
|
controller = Controller.from_port(port=controlport)
|
|
|
|
except SocketError:
|
|
|
|
pass
|
|
|
|
if not controller:
|
|
|
|
sys.exit('Cannot connect to Tor ControlPorts on ports {0}. Is Tor running?'.format(controlports))
|
|
|
|
controller.authenticate()
|
|
|
|
|
2014-05-20 15:44:00 -04:00
|
|
|
# set up hidden service
|
2014-05-21 14:23:37 -04:00
|
|
|
controller.set_options([
|
2014-05-22 14:23:22 -04:00
|
|
|
('HiddenServiceDir', get_hidden_service_dir(port)),
|
2014-05-21 14:23:37 -04:00
|
|
|
('HiddenServicePort', '80 127.0.0.1:{0}'.format(port))
|
|
|
|
])
|
2014-05-22 14:23:22 -04:00
|
|
|
onion_host = get_hidden_service_hostname(port)
|
2014-05-20 15:44:00 -04:00
|
|
|
|
|
|
|
# punch a hole in the firewall
|
2014-05-21 14:51:04 -04:00
|
|
|
tails_open_port(port)
|
2014-05-20 15:44:00 -04:00
|
|
|
|
|
|
|
# instructions
|
2014-05-21 21:17:14 -04:00
|
|
|
print '\nGive this URL to the person you\'re sending the file to:'
|
|
|
|
print 'http://{0}/{1}'.format(onion_host, slug)
|
2014-05-20 15:44:00 -04:00
|
|
|
print ''
|
|
|
|
print 'Press Ctrl-C to stop server\n'
|
|
|
|
|
|
|
|
# start the web server
|
|
|
|
app.run(port=port)
|
|
|
|
print '\n'
|
|
|
|
|
|
|
|
# shutdown
|
2014-05-21 14:51:04 -04:00
|
|
|
tails_close_port(port)
|