Merge branch 'master' into gui

This commit is contained in:
Micah Lee 2014-05-27 19:36:15 -04:00
commit 5524bb4163
275 changed files with 234 additions and 45 deletions

37
.gitignore vendored
View File

@ -1,2 +1,37 @@
*.py[cod]
# C extensions
*.so
# Packages
*.egg
*.egg-info
dist
deb_dist
build
eggs
parts
var
sdist
develop-eggs
.installed.cfg
MANIFEST
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
nosetests.xml
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# vim
*.swp
*.pyc

4
MANIFEST.in Normal file
View File

@ -0,0 +1,4 @@
include LICENSE
include README.md
include onionshare/*.html
include onionshare/strings.json

View File

@ -1,16 +1,22 @@
# OnionShare
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 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.
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.
![Screenshot](/screenshot.png)
## Quick Start
At the moment OnionShare is a command line program. It works in Mac OS X, GNU/Linux, and Windows (see special Windows and Tails instructions below). To get started, either git clone the onionshare repository or [download this zip file](https://github.com/micahflee/onionshare/archive/master.zip) and extract it. Open a terminal and navigate to the onionshare directory.
OnionShare works in GNU/Linux, Mac OS X, and Windows. The easiest way to install it right now is by using pip:
OnionShare relies on Tor. You need to either have a system Tor installed (`sudo apt-get install tor`), or you can open Tor Browser so that OnionShare can use the Tor server provided there. Start Tor, and then run `onionshare.py`, passing in the file that you want to share, like this:
sudo pip install onionshare
[user@dev onionshare]$ ./onionshare.py ~/Desktop/secrets.pdf
More detailed installation instructions for all platforms are coming soon.
## How to Use
OnionShare relies on Tor. You need to either have a system Tor installed (`sudo apt-get install tor`), or you can open Tor Browser so that OnionShare can use the Tor server provided there. Start Tor, and then run `onionshare`, passing in the file that you want to share, like this:
[user@dev onionshare]$ onionshare ~/Desktop/secrets.pdf
Connecting to Tor ControlPort to set up hidden service on port 26828
Give this URL to the person you're sending the file to:
@ -26,13 +32,17 @@ OnionShare relies on Tor. You need to either have a system Tor installed (`sudo
Securely send the URL to the person you are sending the file to (like by using Jabber and OTR). When they load the website in Tor Browser, they will be connecting directly to your computer to download the file. Once you confirm that they have downloaded the file you're sending (ask them if they have the file), press Ctrl-C to shut down the server.
## Using OnionShare in Windows
### Using OnionShare in Tails
OnionShare isn't properly packaged for Windows yet. This mean you'll need to install Python 2.x yourself. [Download the latest 2.x version of python](https://www.python.org/downloads/) for your architecture and install it. Your python binary should be something like `C:\Python27\python.exe`.
See [instructions here](/tails/README.md).
Since OnionShare is a command line program, and using it involves copying and pasting a URL from a command prompt window, it's less frusturating if you use the Windows PowerShell rather than the Command Prompt (in PowerShell, select text you want to copy and then right-click to copy it onto the clipboard). But you can use either. Open either PowerShell or a Command Prompt, cd to your onionshare folder, and run `python.exe onionshare.py` with the path to the file you want to share. For example:
### Using OnionShare in Windows
PS C:\Users\user\Desktop\onionshare> C:\Python27\python.exe onionshare.py C:\Users\user\Desktop\secrets.pdf
OnionShare isn't properly packaged for Windows yet. This means you'll need to install Python 2.x yourself. [Download the latest 2.x version of python](https://www.python.org/downloads/) for your architecture and install it. Your python binary should be something like `C:\Python27\python.exe`.
Since OnionShare is a command line program, and using it involves copying and pasting a URL from a command prompt window, it's less frusturating if you use the Windows PowerShell rather than the Command Prompt (in PowerShell, select text you want to copy and then right-click to copy it onto the clipboard). But you can use either. Open either PowerShell or a Command Prompt, cd to your onionshare folder, and run `python.exe onionshare` with the path to the file you want to share. For example:
PS C:\Users\user\Desktop\onionshare> C:\Python27\python.exe bin\onionshare C:\Users\user\Desktop\secrets.pdf
Connecting to Tor ControlPort to set up hidden service on port 40867
Give this URL to the person you're sending the file to:
@ -48,13 +58,3 @@ Since OnionShare is a command line program, and using it involves copying and pa
127.0.0.1 - - [22/May/2014 11:31:02] "GET /912d927863347b7b97f7a268a4210694/download HTTP/1.1" 200 -
127.0.0.1 - - [22/May/2014 11:31:14] "GET /912d927863347b7b97f7a268a4210694/download HTTP/1.1" 200 -
## Using OnionShare in Tails
You need to run OnionShare as root in Tails, so make sure you set an administrator password when you boot Tails. Follow the same instructions as above, except run `onionshare-tails` instead of `onionshare.py`, and run it with sudo like this:
amnesia@amnesia:~/Persistent/code/onionshare$ sudo ./onionshare-tails ~/Persistent/file_to_send.pgp
[sudo] password for amnesia:
Connecting to Tor ControlPort to set up hidden service on port 16089
Punching a hole in the firewall
In case you're wondering: OnionShare needs root in Tails in order to talk to the Tor ControlPort to create a new hidden service, and also so it can punch a hole in the rigid Tails firewall so that Tor can communicate with the local web server.

10
bin/onionshare Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env python
import sys, os
try:
import onionshare
except ImportError:
sys.path.append(os.path.abspath(os.path.dirname(__file__)+'/..'))
import onionshare
onionshare.main()

1
onionshare/__init__.py Normal file
View File

@ -0,0 +1 @@
from onionshare import *

View File

@ -66,8 +66,8 @@
<p><a class="button" href='/{{ slug }}/download'>{{ filename }} &#x25BC;</a></p>
<div class="metadata">
<p>File size: <strong>{{ filesize }} bytes</strong></p>
<p>SHA1 checksum: <strong>{{ filehash }}</strong></p>
<p>{{strings.filesize}}: <strong>{{ filesize }} bytes</strong></p>
<p>{{strings.sha1_checksum}}: <strong>{{ filehash }}</strong></p>
</div>
</body>
</html>

61
onionshare.py → onionshare/onionshare.py Executable file → Normal file
View File

@ -1,10 +1,15 @@
#!/usr/bin/env python
import os, sys, subprocess, time, hashlib, platform
import os, sys, subprocess, time, hashlib, platform, json, locale, socket
from random import randint
from functools import wraps
sys.path.append(os.path.dirname(__file__)+'/lib')
def get_platform():
if 'ONIONSHARE_PLATFORM' in os.environ:
return os.environ['ONIONSHARE_PLATFORM']
else:
return platform.system()
if get_platform() == 'Tails':
sys.path.append(os.path.dirname(__file__)+'/../tails/lib')
from stem.control import Controller
from stem import SocketError
@ -12,6 +17,8 @@ from stem import SocketError
from flask import Flask, Markup, Response, request, make_response, send_from_directory, render_template_string
app = Flask(__name__)
strings = {}
# generate an unguessable string
slug = os.urandom(16).encode('hex')
@ -22,7 +29,7 @@ filename = filehash = filesize = ''
def index():
global filename, filesize, filehash, slug
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)
slug=slug, filename=os.path.basename(filename), filehash=filehash, filesize=filesize, strings=strings)
@app.route("/{0}/download".format(slug))
def download():
@ -35,12 +42,6 @@ def download():
def page_not_found(e):
return render_template_string(open('{0}/404.html'.format(os.path.dirname(__file__))).read())
def get_platform():
if 'ONIONSHARE_PLATFORM' in os.environ:
return os.environ['ONIONSHARE_PLATFORM']
else:
return platform.system()
def get_hidden_service_dir(port):
if get_platform() == "Windows":
if 'Temp' in os.environ:
@ -57,24 +58,37 @@ def get_hidden_service_hostname(port):
def tails_open_port(port):
if get_platform() == 'Tails':
print 'Punching a hole in the firewall'
print strings["punching_a_hole"]
subprocess.call(['/sbin/iptables', '-I', 'OUTPUT', '-o', 'lo', '-p', 'tcp', '--dport', str(port), '-j', 'ACCEPT'])
def tails_close_port(port):
if get_platform() == 'Tails':
print 'Closing hole in firewall'
print strings["closing_hole"]
subprocess.call(['/sbin/iptables', '-I', 'OUTPUT', '-o', 'lo', '-p', 'tcp', '--dport', str(port), '-j', 'REJECT'])
if __name__ == '__main__':
def load_strings(default="en"):
global strings
translated = json.loads(open('{0}/strings.json'.format(
os.path.dirname(__file__))).read())
strings = translated[default]
lc, enc = locale.getdefaultlocale()
if lc:
lang = lc[:2]
if lang in translated:
strings = translated[lang]
def main():
load_strings()
# validate filename
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))
sys.exit(strings["not_a_file"].format(filename))
# calculate filehash, file size
print 'Calculate sha1 checksum'
print strings["calculating_sha1"]
BLOCKSIZE = 65536
hasher = hashlib.sha1()
with open(filename, 'rb') as f:
@ -85,11 +99,14 @@ if __name__ == '__main__':
filehash = hasher.hexdigest()
filesize = os.path.getsize(filename)
# choose a port
port = randint(1025, 65535)
# let the OS choose a port
tmpsock = socket.socket()
tmpsock.bind(("127.0.0.1", 0))
port = tmpsock.getsockname()[1]
tmpsock.close()
# connect to the tor controlport
print 'Connecting to Tor control port to set up hidden service on port {0}'.format(port)
print strings["connecting_ctrlport"].format(port)
controlports = [9051, 9151]
controller = False
for controlport in controlports:
@ -98,7 +115,7 @@ if __name__ == '__main__':
except SocketError:
pass
if not controller:
sys.exit('Cannot connect to Tor control port on ports {0}. Is Tor running?'.format(controlports))
sys.exit(strings["cant_connect_ctrlport"].format(controlports))
controller.authenticate()
# set up hidden service
@ -112,10 +129,10 @@ if __name__ == '__main__':
tails_open_port(port)
# instructions
print '\nGive this URL to the person you\'re sending the file to:'
print '\n' + strings["give_this_url"]
print 'http://{0}/{1}'.format(onion_host, slug)
print ''
print 'Press Ctrl-C to stop server\n'
print strings["ctrlc_to_stop"]
# start the web server
app.run(port=port)

67
onionshare/strings.json Normal file
View File

@ -0,0 +1,67 @@
{ "en": {
"punching_a_hole": "Punching a hole in the firewall.",
"closing_hole": "Closing hole in firewall.",
"calculating_sha1": "Calculating SHA1 checksum.",
"connecting_ctrlport": "Connecting to Tor control port to set up hidden service on port {0}.",
"cant_connect_ctrlport": "Cannot connect to Tor control port on ports {0}. Is Tor running?",
"give_this_url": "Give this URL to the person you're sending the file to:",
"ctrlc_to_stop": "Press Ctrl-C to stop server",
"not_a_file": "{0} is not a file.",
"filesize": "File size",
"sha1_checksum": "SHA1 checksum"
}, "no": {
"punching_a_hole": "Ã…pner port i brannmuren.",
"closing_hole": "Lukker port i brannmuren.",
"calculating_sha1": "Kalkulerer SHA1 sjekksum.",
"connecting_ctrlport": "Kobler til Tors kontroll-port for å sette opp en gjemt tjeneste på port {0}.",
"cant_connect_ctrlport": "Klarte ikke å koble til Tors kontroll-porter {0}. Sjekk at Tor kjører.",
"give_this_url": "Gi personen du vil sende filen til denne URL-en:",
"ctrlc_to_stop": "Trykk Ctrl+C for å stoppe serveren.",
"not_a_file": "{0} er ikke en fil.",
"filesize": "Filstørrelse",
"sha1_checksum": "SHA1 sjekksum"
}, "es": {
"punching_a_hole": "Abriendo un agujero en el cortafuegos.",
"closing_hole": "Cerrando el agujero en el cortafuegos.",
"calculating_sha1": "Calculando suma de verificación SHA1.",
"connecting_ctrlport": "Conectando a puerto control de Tor para configurar servicio oculto en puerto {0}.",
"cant_connect_ctrlport": "No se pudo conectar a puerto control de Tor en puertos {0}. ¿Está funcionando Tor?",
"give_this_url": "Da esta URL seguramente a la persona para enviar el archivo:",
"ctrlc_to_stop": "Pulse Ctrl-C para detener servidor",
"not_a_file": "{0} no es un archivo.",
"filesize": "Tamaño del archivo",
"sha1_checksum": "Suma de verificación SHA1"
}, "fr": {
"punching_a_hole": "Poinçonnage d'un trou dans le pare-feu.",
"closing_hole": "Trou de clôture dans le pare-feu.",
"calculating_sha1": "Calculer un hachage SHA-1.",
"connecting_ctrlport": "Connexion à réseau Tor utilisant les port {0}.",
"cant_connect_ctrlport": "Réseau Tor indisponible sur le port {0}. Vous utilisez Tor?",
"give_this_url": "Lien de téléchargement:",
"ctrlc_to_stop": "Ctrl-C arrêter le serveur",
"not_a_file": "Ce fichier n'est pas valide {0}.",
"filesize": "Taille de fichier",
"sha1_checksum": "SHA1 hachage"
}, "it": {
"punching_a_hole": "Apertura della porta nel firewall.",
"closing_hole": "Chiusura della porta nel firewall.",
"calculating_sha1": "Calcolo della firma SHA1.",
"connecting_ctrlport": "Connessione alla porta di controllo di Tor per inizializzare il servizio nascosto sulla porta {0}.",
"cant_connect_ctrlport": "Impossibile connettere alla porta di controllo di Tor tramite le porte {0}. Tor è stato avviato?",
"give_this_url": "Comunica questo URL alla persona a cui vuoi inviare il file:",
"ctrlc_to_stop": "Premi Ctrl-C per fermare il server",
"not_a_file": "{0} non è un file.",
"filesize": "Grandezza del file",
"sha1_checksum": "firma SHA1"
}, "fi": {
"punching_a_hole": "Avataan reikä palomuuriin.",
"closing_hole": "Suljetaan palomuurin reikä.",
"calculating_sha1": "Lasketaan SHA1 tarkistussumma.",
"connecting_ctrlport": "Luodaan piilopalvelu porttiin {0} Tor-hallintaportin avulla.",
"cant_connect_ctrlport": "Yhteyttä Tor-hallintaporttiin {0} ei voitu luoda. Onko Tor-ohjelma ajossa?",
"give_this_url": "Anna tämä osoite henkilölle jolle haluat lähettää tiedoston:",
"ctrlc_to_stop": "Paina Ctrl-C pysäyttääksesi palvelun",
"not_a_file": "{0} ei ole tiedosto.",
"filesize": "Tiedoston koko",
"sha1_checksum": "SHA1 tarkistussumma"
}}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 KiB

After

Width:  |  Height:  |  Size: 377 KiB

2
setup.cfg Normal file
View File

@ -0,0 +1,2 @@
[wheel]
universal = 1

32
setup.py Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, sys, subprocess
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
if sys.argv[-1] == 'publish':
subprocess.call(['python', 'setup.py', 'sdist', 'upload', '--sign'])
sys.exit()
setup(
name='onionshare',
version='0.1',
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.""",
author='Micah Lee',
author_email='micah@micahflee.com',
url='https://github.com/micahflee/onionshare',
include_package_data=True,
install_requires=[
'flask >= 0.10.1',
'stem >= 1.1.1'
],
license="GPL v3",
keywords='onion, share, onionshare, tor, anonymous, web server',
packages=['onionshare'],
scripts=['bin/onionshare']
)

21
tails/README.md Normal file
View File

@ -0,0 +1,21 @@
# Running OnionShare in Tails
It's tricky to get all of the correct python dependencies in [Tails](https://tails.boum.org/). Until OnionShare is properly packaged in Debian (and their dependencies, flask and stem, are also packaged in the version of Debian that Tails is based on) and can just be [auto-installed on boot](https://tails.boum.org/doc/first_steps/persistence/configure/index.en.html#index13h2), this is a hack to get it working.
Run the `tails-onionshare` binary in this folder as root, and OnionShare will use the libraries in the lib folder so they don't have to be installed system-wide.
amnesia@amnesia:~/Persistent/onionshare/tails$ sudo ./tails-onionshare /home/amnesia/Persistent/secrets.pdf
[sudo] password for amnesia:
Calculating SHA1 checksum.
Connecting to Tor control port to set up hidden service on port 39465.
Punching a hole in the firewall.
Give this URL to the person you're sending the file to:
http://sq64tkg4fxoscwns.onion/42b60c759a1ae438337dc797e910b60e
Press Ctrl-C to stop server
* Running on http://127.0.0.1:39465/
127.0.0.1 - - [27/May/2014 21:05:32] "GET /42b60c759a1ae438337dc797e910b60e HTTP/1.1" 200 -
127.0.0.1 - - [27/May/2014 21:05:36] "GET /favicon.ico HTTP/1.1" 200 -
127.0.0.1 - - [27/May/2014 21:05:36] "GET /favicon.ico HTTP/1.1" 200 -

Some files were not shown because too many files have changed in this diff Show More