[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