mirror of
https://github.com/onionshare/onionshare.git
synced 2025-01-13 16:29:31 -05:00
server can be started and stopped from the GUI
This commit is contained in:
parent
9cb1871b02
commit
349ca67cc9
@ -154,6 +154,22 @@ def page_not_found(e):
|
||||
add_request(REQUEST_OTHER, request.path)
|
||||
return render_template_string(open('{0}/404.html'.format(helpers.get_onionshare_dir())).read())
|
||||
|
||||
# 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')):
|
||||
abort(404)
|
||||
|
||||
# shutdown the flask service
|
||||
func = request.environ.get('werkzeug.server.shutdown')
|
||||
if func is None:
|
||||
raise RuntimeError('Not running with the Werkzeug Server')
|
||||
func()
|
||||
|
||||
return ""
|
||||
|
||||
def start(port, stay_open=False):
|
||||
set_stay_open(stay_open)
|
||||
app.run(port=port)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
from __future__ import division
|
||||
import os, sys, subprocess, inspect, platform, argparse, threading, time, math, inspect, platform
|
||||
import os, sys, subprocess, inspect, platform, argparse, threading, time, math, inspect, platform, urllib2
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
import common
|
||||
@ -31,7 +31,7 @@ class OnionShareGui(QtGui.QWidget):
|
||||
self.setWindowTitle('OnionShare')
|
||||
self.setWindowIcon(window_icon)
|
||||
|
||||
def start_send(self, filenames=None):
|
||||
def send_files(self, filenames=None):
|
||||
# file selection
|
||||
file_selection = FileSelection()
|
||||
if filenames:
|
||||
@ -39,10 +39,12 @@ class OnionShareGui(QtGui.QWidget):
|
||||
file_selection.file_list.add_file(filename)
|
||||
|
||||
# server status
|
||||
server_status = ServerStatus(file_selection)
|
||||
server_status.server_started.connect(file_selection.server_started)
|
||||
server_status.server_stopped.connect(file_selection.server_stopped)
|
||||
file_selection.file_list.files_updated.connect(server_status.update)
|
||||
self.server_status = ServerStatus(file_selection)
|
||||
self.server_status.server_started.connect(file_selection.server_started)
|
||||
self.server_status.server_started.connect(self.start_server)
|
||||
self.server_status.server_stopped.connect(file_selection.server_stopped)
|
||||
self.server_status.server_stopped.connect(self.stop_server)
|
||||
file_selection.file_list.files_updated.connect(self.server_status.update)
|
||||
|
||||
# downloads
|
||||
downloads = Downloads()
|
||||
@ -53,254 +55,33 @@ class OnionShareGui(QtGui.QWidget):
|
||||
# main layout
|
||||
self.layout = QtGui.QVBoxLayout()
|
||||
self.layout.addLayout(file_selection)
|
||||
self.layout.addLayout(server_status)
|
||||
self.layout.addLayout(self.server_status)
|
||||
self.layout.addLayout(downloads)
|
||||
self.layout.addLayout(options)
|
||||
self.setLayout(self.layout)
|
||||
self.show()
|
||||
|
||||
"""
|
||||
# initialize ui
|
||||
self.init_ui(filename, basename)
|
||||
# check for requests every 1000ms
|
||||
self.timer = QtCore.QTimer()
|
||||
QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.check_for_requests)
|
||||
self.timer.start(1000)
|
||||
# copy url to clipboard
|
||||
self.copy_to_clipboard()
|
||||
|
||||
def init_ui(self, filename, basename):
|
||||
# window
|
||||
self.setWindowTitle(u"{0} | OnionShare".format(basename.decode("utf-8")))
|
||||
self.resize(580, 400)
|
||||
self.setMinimumSize(580, 400)
|
||||
self.setMaximumSize(580, 400)
|
||||
palette = QtGui.QPalette()
|
||||
palette.setColor(QtGui.QPalette.Background, QtCore.Qt.white)
|
||||
self.setPalette(palette)
|
||||
|
||||
# icon
|
||||
self.setWindowIcon(window_icon)
|
||||
|
||||
# widget
|
||||
self.widget = QtGui.QWidget(self)
|
||||
self.widget.setGeometry(QtCore.QRect(5, 5, 570, 390))
|
||||
|
||||
# wrapper
|
||||
self.wrapper = QtGui.QVBoxLayout(self.widget)
|
||||
self.wrapper.setMargin(0)
|
||||
self.wrapper.setObjectName("wrapper")
|
||||
|
||||
# header
|
||||
self.header = QtGui.QHBoxLayout()
|
||||
|
||||
# logo
|
||||
self.logoLabel = QtGui.QLabel(self.widget)
|
||||
self.logo = QtGui.QPixmap("{0}/static/logo.png".format(common.onionshare_gui_dir))
|
||||
self.logoLabel.setPixmap(self.logo)
|
||||
self.header.addWidget(self.logoLabel)
|
||||
|
||||
# fileinfo
|
||||
self.fileinfo = QtGui.QVBoxLayout()
|
||||
|
||||
# filename
|
||||
self.filenameLabel = QtGui.QLabel(self.widget)
|
||||
self.filenameLabel.setStyleSheet("font-family: sans-serif; font-size: 22px; font-weight: bold; color: #000000; white-space: nowrap")
|
||||
self.filenameLabel.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
self.fileinfo.addWidget(self.filenameLabel)
|
||||
|
||||
# checksum
|
||||
self.checksumLabel = QtGui.QLabel(self.widget)
|
||||
self.checksumLabel.setStyleSheet("font-family: arial; text-align: left; color: #666666")
|
||||
self.checksumLabel.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
self.fileinfo.addWidget(self.checksumLabel)
|
||||
|
||||
# filesize
|
||||
self.filesizeLabel = QtGui.QLabel(self.widget)
|
||||
self.filesizeLabel.setStyleSheet("font-family: arial; text-align: left; color: #666666")
|
||||
self.filesizeLabel.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
self.fileinfo.addWidget(self.filesizeLabel)
|
||||
self.header.addLayout(self.fileinfo)
|
||||
|
||||
fileinfoSpacer = QtGui.QSpacerItem(20, 50, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Maximum)
|
||||
self.header.addItem(fileinfoSpacer)
|
||||
self.wrapper.addLayout(self.header)
|
||||
|
||||
# header seperator
|
||||
self.headerSeperator = QtGui.QFrame(self.widget)
|
||||
self.headerSeperator.setFrameShape(QtGui.QFrame.HLine)
|
||||
self.headerSeperator.setFrameShadow(QtGui.QFrame.Plain)
|
||||
self.wrapper.addWidget(self.headerSeperator)
|
||||
|
||||
# log
|
||||
self.log = QtGui.QVBoxLayout()
|
||||
self.log.setAlignment(QtCore.Qt.AlignTop)
|
||||
self.wrapper.addLayout(self.log)
|
||||
spacerItem2 = QtGui.QSpacerItem(1, 400, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Maximum)
|
||||
self.wrapper.addItem(spacerItem2)
|
||||
|
||||
# footer seperator
|
||||
self.footerSeperator = QtGui.QFrame(self.widget)
|
||||
self.footerSeperator.setFrameShape(QtGui.QFrame.HLine)
|
||||
self.footerSeperator.setFrameShadow(QtGui.QFrame.Plain)
|
||||
self.wrapper.addWidget(self.footerSeperator)
|
||||
|
||||
# footer
|
||||
self.footer = QtGui.QHBoxLayout()
|
||||
|
||||
# close automatically checkbox
|
||||
self.closeAutomatically = QtGui.QCheckBox(self.widget)
|
||||
self.closeAutomatically.setCheckState(QtCore.Qt.Checked)
|
||||
if web.get_stay_open():
|
||||
self.closeAutomatically.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
self.closeAutomatically.setStyleSheet("font-size: 12px")
|
||||
self.connect(self.closeAutomatically, QtCore.SIGNAL('stateChanged(int)'), self.stay_open_changed)
|
||||
self.footer.addWidget(self.closeAutomatically)
|
||||
|
||||
# footer spacer
|
||||
spacerItem1 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.footer.addItem(spacerItem1)
|
||||
|
||||
# copy url button
|
||||
self.copyURL = QtGui.QPushButton(self.widget)
|
||||
self.connect(self.copyURL, QtCore.SIGNAL("clicked()"), self.copy_to_clipboard)
|
||||
|
||||
self.footer.addWidget(self.copyURL)
|
||||
self.wrapper.addLayout(self.footer)
|
||||
|
||||
url = 'http://{0}/{1}'.format(self.app.onion_host, web.slug)
|
||||
|
||||
filehash, filesize = helpers.file_crunching(filename)
|
||||
web.set_file_info(filename, filehash, filesize)
|
||||
def start_server(self):
|
||||
# start the hidden service
|
||||
try:
|
||||
self.app.start_hidden_service(gui=True)
|
||||
except onionshare.NoTor as e:
|
||||
alert(e.args[0], QtGui.QMessageBox.Warning)
|
||||
self.server_status.stop_server()
|
||||
return
|
||||
except onionshare.TailsError as e:
|
||||
alert(e.args[0], QtGui.QMessageBox.Warning)
|
||||
self.server_status.stop_server()
|
||||
return
|
||||
|
||||
# start onionshare service in new thread
|
||||
t = threading.Thread(target=web.start, args=(self.app.port, self.app.stay_open))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
# show url to share
|
||||
loaded = QtGui.QLabel(strings._("give_this_url") + "<br /><strong>" + url + "</strong>")
|
||||
loaded.setStyleSheet("color: #000000; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
|
||||
loaded.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
self.log.addWidget(loaded)
|
||||
|
||||
# translate
|
||||
self.filenameLabel.setText(basename)
|
||||
self.checksumLabel.setText(strings._("sha1_checksum") + ": <strong>" + filehash + "</strong>")
|
||||
self.filesizeLabel.setText(strings._("filesize") + ": <strong>" + helpers.human_readable_filesize(filesize) + "</strong>")
|
||||
self.closeAutomatically.setText(strings._("close_on_finish"))
|
||||
self.copyURL.setText(strings._("copy_url"))
|
||||
|
||||
# show dialog
|
||||
self.show()
|
||||
|
||||
def update_log(self, event, msg):
|
||||
global progress
|
||||
if event["type"] == web.REQUEST_LOAD:
|
||||
label = QtGui.QLabel(msg)
|
||||
label.setStyleSheet("color: #009900; font-weight: bold; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
|
||||
label.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
self.log.addWidget(label)
|
||||
elif event["type"] == web.REQUEST_DOWNLOAD:
|
||||
download = QtGui.QLabel(msg)
|
||||
download.setStyleSheet("color: #009900; font-weight: bold; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
|
||||
download.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
self.log.addWidget(download)
|
||||
progress = QtGui.QLabel()
|
||||
progress.setStyleSheet("color: #0000cc; font-weight: bold; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
|
||||
progress.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
self.log.addWidget(progress)
|
||||
elif event["type"] == web.REQUEST_PROGRESS:
|
||||
progress.setText(msg)
|
||||
elif event["path"] != '/favicon.ico':
|
||||
other = QtGui.QLabel(msg)
|
||||
other.setStyleSheet("color: #009900; font-weight: bold; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
|
||||
other.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
self.log.addWidget(other)
|
||||
return
|
||||
|
||||
def check_for_requests(self):
|
||||
events = []
|
||||
|
||||
done = False
|
||||
while not done:
|
||||
try:
|
||||
r = web.q.get(False)
|
||||
events.append(r)
|
||||
except web.Queue.Empty:
|
||||
done = True
|
||||
|
||||
for event in events:
|
||||
if event["type"] == web.REQUEST_LOAD:
|
||||
self.update_log(event, strings._("download_page_loaded"))
|
||||
elif event["type"] == web.REQUEST_DOWNLOAD:
|
||||
self.update_log(event, strings._("download_started"))
|
||||
elif event["type"] == web.REQUEST_PROGRESS:
|
||||
# is the download complete?
|
||||
if event["data"]["bytes"] == web.filesize:
|
||||
self.update_log(event, strings._("download_finished"))
|
||||
# close on finish?
|
||||
if not web.get_stay_open():
|
||||
time.sleep(1)
|
||||
def close_countdown(i):
|
||||
if i > 0:
|
||||
QtGui.QApplication.quit()
|
||||
else:
|
||||
time.sleep(1)
|
||||
i -= 1
|
||||
closing.setText(strings._("close_countdown").format(str(i)))
|
||||
print strings._("close_countdown").format(str(i))
|
||||
close_countdown(i)
|
||||
|
||||
closing = QtGui.QLabel(self.widget)
|
||||
closing.setStyleSheet("font-weight: bold; font-style: italic; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
|
||||
closing.setText(strings._("close_countdown").format("3"))
|
||||
closing.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
self.log.addWidget(closing)
|
||||
close_countdown(3)
|
||||
|
||||
# still in progress
|
||||
else:
|
||||
percent = math.floor((event["data"]["bytes"] / web.filesize) * 100)
|
||||
self.update_log(event, " " + helpers.human_readable_filesize(event["data"]["bytes"]) + ', ' + str(percent) +'%')
|
||||
|
||||
elif event["path"] != '/favicon.ico':
|
||||
self.update_log(event, strings._("other_page_loaded"))
|
||||
|
||||
def copy_to_clipboard(self):
|
||||
url = 'http://{0}/{1}'.format(self.app.onion_host, web.slug)
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
# Qt's QClipboard isn't working in Windows
|
||||
# https://github.com/micahflee/onionshare/issues/46
|
||||
import ctypes
|
||||
GMEM_DDESHARE = 0x2000
|
||||
ctypes.windll.user32.OpenClipboard(None)
|
||||
ctypes.windll.user32.EmptyClipboard()
|
||||
hcd = ctypes.windll.kernel32.GlobalAlloc(GMEM_DDESHARE, len(bytes(url))+1)
|
||||
pch_data = ctypes.windll.kernel32.GlobalLock(hcd)
|
||||
ctypes.cdll.msvcrt.strcpy(ctypes.c_char_p(pch_data), bytes(url))
|
||||
ctypes.windll.kernel32.GlobalUnlock(hcd)
|
||||
ctypes.windll.user32.SetClipboardData(1, hcd)
|
||||
ctypes.windll.user32.CloseClipboard()
|
||||
else:
|
||||
clipboard = qtapp.clipboard()
|
||||
clipboard.setText(url)
|
||||
|
||||
copied = QtGui.QLabel(strings._("copied_url"))
|
||||
copied.setStyleSheet("font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
|
||||
copied.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
|
||||
self.log.addWidget(copied)
|
||||
return
|
||||
|
||||
def stay_open_changed(self, state):
|
||||
if state > 0:
|
||||
web.set_stay_open(False)
|
||||
else:
|
||||
web.set_stay_open(True)
|
||||
return
|
||||
"""
|
||||
def stop_server(self):
|
||||
# to stop flask, load http://127.0.0.1:<port>/<shutdown_slug>/shutdown
|
||||
urllib2.urlopen('http://127.0.0.1:{0}/{1}/shutdown'.format(self.app.port, web.shutdown_slug)).read()
|
||||
|
||||
def alert(msg, icon=QtGui.QMessageBox.NoIcon):
|
||||
dialog = QtGui.QMessageBox()
|
||||
@ -352,16 +133,6 @@ def main():
|
||||
web.set_stay_open(stay_open)
|
||||
app = onionshare.OnionShare(debug, local_only, stay_open)
|
||||
|
||||
"""try:
|
||||
app.start_hidden_service(gui=True)
|
||||
except onionshare.NoTor as e:
|
||||
alert(e.args[0], QtGui.QMessageBox.Warning)
|
||||
sys.exit()
|
||||
except onionshare.TailsError as e:
|
||||
alert(e.args[0], QtGui.QMessageBox.Warning)
|
||||
sys.exit()
|
||||
"""
|
||||
|
||||
# clean up when app quits
|
||||
def shutdown():
|
||||
app.cleanup()
|
||||
@ -369,7 +140,7 @@ def main():
|
||||
|
||||
# launch the gui
|
||||
gui = OnionShareGui(app)
|
||||
gui.start_send(filenames)
|
||||
gui.send_files(filenames)
|
||||
|
||||
# all done
|
||||
sys.exit(qtapp.exec_())
|
||||
|
Loading…
Reference in New Issue
Block a user