mirror of
https://github.com/onionshare/onionshare.git
synced 2024-10-01 01:35:40 -04:00
Moved hidden service login into separate file. Prefer to use ephemeral hidden services now if they are available. Ephermal does not yet work, but old hidservdir still works.
This commit is contained in:
parent
bbee1599c5
commit
eba6dbb843
@ -43,5 +43,6 @@
|
||||
"gui_starting_server3": "Waiting for Tor hidden service...",
|
||||
"gui_please_wait": "Please wait...",
|
||||
"error_hs_dir_cannot_create": "Cannot create hidden service dir {0:s}",
|
||||
"error_hs_dir_not_writable": "Hidden service dir {0:s} is not writable"
|
||||
"error_hs_dir_not_writable": "Hidden service dir {0:s} is not writable",
|
||||
"using_ephemeral": "Using ephemeral Tor hidden service"
|
||||
}
|
||||
|
140
onionshare/hs.py
Normal file
140
onionshare/hs.py
Normal file
@ -0,0 +1,140 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
OnionShare | https://onionshare.org/
|
||||
|
||||
Copyright (C) 2015 Micah Lee <micah@micahflee.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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/>.
|
||||
"""
|
||||
|
||||
from stem.control import Controller
|
||||
import os, tempfile, shutil
|
||||
|
||||
import helpers, strings
|
||||
|
||||
class NoTor(Exception):
|
||||
pass
|
||||
|
||||
class HSDirError(Exception):
|
||||
pass
|
||||
|
||||
class HS(object):
|
||||
def __init__(self, transparent_torification=False):
|
||||
self.transparent_torification = transparent_torification
|
||||
|
||||
# files and dirs to delete on shutdown
|
||||
self.cleanup_filenames = []
|
||||
|
||||
# connect to the tor controlport
|
||||
self.c = None
|
||||
ports = [9051, 9151]
|
||||
for port in ports:
|
||||
try:
|
||||
self.c = Controller.from_port(port=port)
|
||||
self.c.authenticate()
|
||||
break
|
||||
except:
|
||||
pass
|
||||
if not self.c:
|
||||
raise NoTor(strings._("cant_connect_ctrlport").format(ports))
|
||||
|
||||
# do the versions of stem and tor that I'm using support ephemeral hidden services?
|
||||
tor_version = self.c.get_version().version_str
|
||||
list_ephemeral_hidden_services = getattr(self.c, "list_ephemeral_hidden_services", None)
|
||||
self.supports_ephemeral = callable(list_ephemeral_hidden_services) and tor_version >= '0.2.7.1'
|
||||
|
||||
def start(self, port):
|
||||
if self.supports_ephemeral:
|
||||
print strings._('using_ephemeral')
|
||||
res = self.c.create_ephemeral_hidden_service(port)
|
||||
onion_host = res.content()[0][2].split('=')[1] + '.onion'
|
||||
return onion_host
|
||||
|
||||
else:
|
||||
# come up with a hidden service directory name
|
||||
if helpers.get_platform() == 'Windows':
|
||||
path = '{0:s}/onionshare'.format(os.environ['Temp'].replace('\\', '/'))
|
||||
else:
|
||||
path = '/tmp/onionshare'
|
||||
|
||||
try:
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path, 0700)
|
||||
except:
|
||||
raise HSDirError(strings._("error_hs_dir_cannot_create").format(path))
|
||||
if not os.access(path, os.W_OK):
|
||||
raise HSDirError(strings._("error_hs_dir_not_writable").format(path))
|
||||
|
||||
hidserv_dir = tempfile.mkdtemp(dir=path)
|
||||
self.cleanup_filenames.append(hidserv_dir)
|
||||
|
||||
# set up hidden service
|
||||
hsdic = self.c.get_conf_map('HiddenServiceOptions') or {
|
||||
'HiddenServiceDir': [], 'HiddenServicePort': []
|
||||
}
|
||||
if hidserv_dir in hsdic.get('HiddenServiceDir', []):
|
||||
# Maybe a stale service with the wrong local port
|
||||
dropme = hsdic['HiddenServiceDir'].index(hidserv_dir)
|
||||
del hsdic['HiddenServiceDir'][dropme]
|
||||
del hsdic['HiddenServicePort'][dropme]
|
||||
hsdic['HiddenServiceDir'] = hsdic.get('HiddenServiceDir', [])+[hidserv_dir]
|
||||
hsdic['HiddenServicePort'] = hsdic.get('HiddenServicePort', [])+[
|
||||
'80 127.0.0.1:{0:d}'.format(port)]
|
||||
|
||||
self.c.set_options(self._hsdic2list(hsdic))
|
||||
|
||||
# figure out the .onion hostname
|
||||
hostname_file = '{0:s}/hostname'.format(hidserv_dir)
|
||||
onion_host = open(hostname_file, 'r').read().strip()
|
||||
return onion_host
|
||||
|
||||
def cleanup(self):
|
||||
if self.supports_ephemeral:
|
||||
# todo: cleanup the ephemeral hidden service
|
||||
pass
|
||||
else:
|
||||
# cleanup hidden service
|
||||
try:
|
||||
if self.controller:
|
||||
# Get fresh hidden services (maybe changed since last time)
|
||||
# and remove ourselves
|
||||
hsdic = self.controller.get_conf_map('HiddenServiceOptions') or {
|
||||
'HiddenServiceDir': [], 'HiddenServicePort': []
|
||||
}
|
||||
if self.hidserv_dir and self.hidserv_dir in hsdic.get('HiddenServiceDir', []):
|
||||
dropme = hsdic['HiddenServiceDir'].index(self.hidserv_dir)
|
||||
del hsdic['HiddenServiceDir'][dropme]
|
||||
del hsdic['HiddenServicePort'][dropme]
|
||||
self.controller.set_options(self._hsdic2list(hsdic))
|
||||
# Politely close the controller
|
||||
self.controller.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
# cleanup files
|
||||
for filename in self.cleanup_filenames:
|
||||
if os.path.isfile(filename):
|
||||
os.remove(filename)
|
||||
elif os.path.isdir(filename):
|
||||
shutil.rmtree(filename)
|
||||
self.cleanup_filenames = []
|
||||
|
||||
def _hsdic2list(self, dic):
|
||||
"""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])]
|
||||
for vals in zip(dic.get('HiddenServiceDir', []), dic.get('HiddenServicePort', []))
|
||||
] for pair in pairs
|
||||
]
|
@ -17,38 +17,20 @@ 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 os, sys, subprocess, time, argparse, inspect, shutil, socket, threading, urllib2, httplib, tempfile
|
||||
import os, sys, subprocess, time, argparse, inspect, shutil, socket, threading, urllib2, httplib
|
||||
import socks
|
||||
|
||||
from stem.control import Controller
|
||||
|
||||
import strings, helpers, web
|
||||
|
||||
|
||||
class NoTor(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class HSDirError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def hsdic2list(dic):
|
||||
"""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])]
|
||||
for vals in zip(dic.get('HiddenServiceDir', []), dic.get('HiddenServicePort', []))
|
||||
] for pair in pairs
|
||||
]
|
||||
|
||||
import strings, helpers, web, hs
|
||||
|
||||
class OnionShare(object):
|
||||
def __init__(self, debug=False, local_only=False, stay_open=False, transparent_torification=False):
|
||||
self.port = None
|
||||
self.controller = None
|
||||
self.hs = None
|
||||
self.hidserv_dir = None
|
||||
|
||||
# files and dirs to delete on shutdown
|
||||
self.cleanup_filenames = []
|
||||
|
||||
# debug mode
|
||||
if debug:
|
||||
web.debug_mode()
|
||||
@ -62,36 +44,6 @@ class OnionShare(object):
|
||||
# traffic automatically goes through Tor
|
||||
self.transparent_torification = transparent_torification
|
||||
|
||||
# files and dirs to delete on shutdown
|
||||
self.cleanup_filenames = []
|
||||
|
||||
def cleanup(self):
|
||||
# cleanup hidden service
|
||||
try:
|
||||
if self.controller:
|
||||
# Get fresh hidden services (maybe changed since last time)
|
||||
# and remove ourselves
|
||||
hsdic = self.controller.get_conf_map('HiddenServiceOptions') or {
|
||||
'HiddenServiceDir': [], 'HiddenServicePort': []
|
||||
}
|
||||
if self.hidserv_dir and self.hidserv_dir in hsdic.get('HiddenServiceDir', []):
|
||||
dropme = hsdic['HiddenServiceDir'].index(self.hidserv_dir)
|
||||
del hsdic['HiddenServiceDir'][dropme]
|
||||
del hsdic['HiddenServicePort'][dropme]
|
||||
self.controller.set_options(hsdic2list(hsdic))
|
||||
# Politely close the controller
|
||||
self.controller.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
# cleanup files
|
||||
for filename in self.cleanup_filenames:
|
||||
if os.path.isfile(filename):
|
||||
os.remove(filename)
|
||||
elif os.path.isdir(filename):
|
||||
shutil.rmtree(filename)
|
||||
self.cleanup_filenames = []
|
||||
|
||||
def choose_port(self):
|
||||
# let the OS choose a port
|
||||
tmpsock = socket.socket()
|
||||
@ -107,54 +59,10 @@ class OnionShare(object):
|
||||
self.onion_host = '127.0.0.1:{0:d}'.format(self.port)
|
||||
return
|
||||
|
||||
# come up with a hidden service directory name
|
||||
if helpers.get_platform() == 'Windows':
|
||||
path = '{0:s}/onionshare'.format(os.environ['Temp'].replace('\\', '/'))
|
||||
else:
|
||||
path = '/tmp/onionshare'
|
||||
if not self.hs:
|
||||
self.hs = hs.HS(self.transparent_torification)
|
||||
|
||||
try:
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path, 0700)
|
||||
except:
|
||||
raise HSDirError(strings._("error_hs_dir_cannot_create").format(path))
|
||||
if not os.access(path, os.W_OK):
|
||||
raise HSDirError(strings._("error_hs_dir_not_writable").format(path))
|
||||
|
||||
self.hidserv_dir = tempfile.mkdtemp(dir=path)
|
||||
self.cleanup_filenames.append(self.hidserv_dir)
|
||||
|
||||
# connect to the tor controlport
|
||||
self.controller = None
|
||||
tor_control_ports = [9051, 9151]
|
||||
for tor_control_port in tor_control_ports:
|
||||
try:
|
||||
self.controller = Controller.from_port(port=tor_control_port)
|
||||
self.controller.authenticate()
|
||||
break
|
||||
except:
|
||||
pass
|
||||
if not self.controller:
|
||||
raise NoTor(strings._("cant_connect_ctrlport").format(tor_control_ports))
|
||||
|
||||
# set up hidden service
|
||||
hsdic = self.controller.get_conf_map('HiddenServiceOptions') or {
|
||||
'HiddenServiceDir': [], 'HiddenServicePort': []
|
||||
}
|
||||
if self.hidserv_dir in hsdic.get('HiddenServiceDir', []):
|
||||
# Maybe a stale service with the wrong local port
|
||||
dropme = hsdic['HiddenServiceDir'].index(self.hidserv_dir)
|
||||
del hsdic['HiddenServiceDir'][dropme]
|
||||
del hsdic['HiddenServicePort'][dropme]
|
||||
hsdic['HiddenServiceDir'] = hsdic.get('HiddenServiceDir', [])+[self.hidserv_dir]
|
||||
hsdic['HiddenServicePort'] = hsdic.get('HiddenServicePort', [])+[
|
||||
'80 127.0.0.1:{0:d}'.format(self.port)]
|
||||
|
||||
self.controller.set_options(hsdic2list(hsdic))
|
||||
|
||||
# figure out the .onion hostname
|
||||
hostname_file = '{0:s}/hostname'.format(self.hidserv_dir)
|
||||
self.onion_host = open(hostname_file, 'r').read().strip()
|
||||
self.onion_host = self.hs.start(self.port)
|
||||
|
||||
def wait_for_hs(self):
|
||||
if self.local_only:
|
||||
@ -173,11 +81,11 @@ class OnionShare(object):
|
||||
urllib2.urlopen('http://{0:s}'.format(self.onion_host))
|
||||
else:
|
||||
tor_exists = False
|
||||
tor_socks_ports = [9050, 9150]
|
||||
for tor_socks_port in tor_socks_ports:
|
||||
ports = [9050, 9150]
|
||||
for port in ports:
|
||||
try:
|
||||
s = socks.socksocket()
|
||||
s.setproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', tor_socks_port)
|
||||
s.setproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', port)
|
||||
s.connect((self.onion_host, 80))
|
||||
s.close()
|
||||
tor_exists = True
|
||||
@ -202,6 +110,18 @@ class OnionShare(object):
|
||||
return False
|
||||
return True
|
||||
|
||||
def cleanup(self):
|
||||
# cleanup files
|
||||
for filename in self.cleanup_filenames:
|
||||
if os.path.isfile(filename):
|
||||
os.remove(filename)
|
||||
elif os.path.isdir(filename):
|
||||
shutil.rmtree(filename)
|
||||
self.cleanup_filenames = []
|
||||
|
||||
# call hs's cleanup
|
||||
self.hs.cleanup()
|
||||
|
||||
|
||||
def main(cwd=None):
|
||||
strings.load_strings()
|
||||
@ -244,9 +164,9 @@ def main(cwd=None):
|
||||
app.choose_port()
|
||||
print strings._("connecting_ctrlport").format(int(app.port))
|
||||
app.start_hidden_service()
|
||||
except NoTor as e:
|
||||
except hs.NoTor as e:
|
||||
sys.exit(e.args[0])
|
||||
except HSDirError as e:
|
||||
except hs.HSDirError as e:
|
||||
sys.exit(e.args[0])
|
||||
|
||||
# prepare files to share
|
||||
|
Loading…
Reference in New Issue
Block a user