[Pkg-anonymity-tools] [onionshare] 40/140: server can be started and stopped from the GUI
Ulrike Uhlig
u-guest at moszumanska.debian.org
Mon Sep 29 20:33:45 UTC 2014
This is an automated email from the git hooks/post-receive script.
u-guest pushed a commit to branch master
in repository onionshare.
commit 349ca67cc9ffefdff6ea92bee62c4c31b95a8691
Author: Micah Lee <micah at micahflee.com>
Date: Wed Aug 27 17:52:45 2014 -0700
server can be started and stopped from the GUI
---
onionshare/web.py | 16 +++
onionshare_gui/onionshare_gui.py | 279 ++++-----------------------------------
2 files changed, 41 insertions(+), 254 deletions(-)
diff --git a/onionshare/web.py b/onionshare/web.py
index c9e2a6a..243c390 100644
--- a/onionshare/web.py
+++ b/onionshare/web.py
@@ -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)
+ at 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)
+
diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py
index 5d0cae0..d3b0c1a 100644
--- a/onionshare_gui/onionshare_gui.py
+++ b/onionshare_gui/onionshare_gui.py
@@ -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_())
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/onionshare.git
More information about the Pkg-anonymity-tools
mailing list