summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkali <kali@leap.se>2017-08-02 18:40:21 -0700
committerKali Kaneko <kali@leap.se>2017-08-14 18:09:06 -0400
commit9c74ffb925325de98e8dd73acdf1602dd40bfcc0 (patch)
treeb0cb7e5ab25b86927c2c95d51df172ae91824986
parente40e28b51312cd1e257022bfcb74b37d619dc0ea (diff)
[pkg] working bundle in osx using pywebview + pyobjc
-rw-r--r--pkg/pyinst/app.spec28
-rw-r--r--pkg/pyinst/build.mk3
-rw-r--r--src/leap/bitmask/gui/app2.py144
3 files changed, 164 insertions, 11 deletions
diff --git a/pkg/pyinst/app.spec b/pkg/pyinst/app.spec
index a14dbcb5..9e99d7e9 100644
--- a/pkg/pyinst/app.spec
+++ b/pkg/pyinst/app.spec
@@ -1,10 +1,12 @@
# -*- mode: python -*-
-import platform
+import os
import sys
+import platform
block_cipher = None
IS_MAC = sys.platform.startswith('darwin')
+IS_WIN = platform.system() == 'Windows'
BITMASK_VERSION = open('pkg/next-version').read()
if IS_MAC:
@@ -19,7 +21,6 @@ hiddenimports = [
'pysqlcipher', 'service_identity',
'leap.common', 'leap.bitmask',
'leap.bitmask.core.logs',
- 'leap.bitmask.gui.icons_rc',
'leap.soledad.common',
'leap.soledad.common.document',
'leap.soledad.common.l2db',
@@ -28,7 +29,7 @@ hiddenimports = [
'packaging', 'packaging.version', 'packaging.specifiers',
'packaging.requirements']
-if platform.system() == 'Windows':
+if IS_WIN:
print "Platform=Windows, using pyside..."
hiddenimports.extend(
['PySide.QtCore', 'PySide.QtGui', 'PySide.QtWebKit',
@@ -39,19 +40,28 @@ if platform.system() == 'Windows':
'packaging.requirements',
'python-gnupg'])
excludes = ['PyQt5']
+ QT5PATH = ['']
+elif IS_MAC:
+ hiddenimports.extend(['pywebview', 'pyobjc'])
+ excludes = ['PyQt5', 'IPython', 'PySide']
+ QT5PATH = ['']
else:
hiddenimports.extend(
- ['PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtWebKit'])
+ ['PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtWebEngine',
+ 'leap.bitmask.gui.icons_rc'])
excludes = ['PySide']
-import os
VENV = os.environ.get('VIRTUAL_ENV', '')
-a = Analysis(['../../src/leap/bitmask/gui/app.py'],
+if IS_MAC:
+ # experimental pywebview entrypoint
+ ENTRYPOINT = ['../../src/leap/bitmask/gui/app2.py']
+else:
+ ENTRYPOINT = ['../../src/leap/bitmask/gui/app.py']
+
+a = Analysis(ENTRYPOINT,
pathex=[
- '/usr/lib/python2.7/dist-packages/',
- VENV + '/Lib/site-packages/',
- VENV + '/Lib/site-packages/leap/soledad'],
+ '/usr/lib/python2.7/dist-packages/'] + QT5PATH,
binaries=None,
datas=None,
hiddenimports=hiddenimports,
diff --git a/pkg/pyinst/build.mk b/pkg/pyinst/build.mk
index a9df4974..b6dea151 100644
--- a/pkg/pyinst/build.mk
+++ b/pkg/pyinst/build.mk
@@ -11,7 +11,7 @@ bundle: bundle_clean
pyinstaller -y pkg/pyinst/app.spec
cp $(VIRTUAL_ENV)/lib/python2.7/site-packages/_scrypt.so $(DIST)
cp src/leap/bitmask/core/bitmaskd.tac $(DIST)
- mkdir $(DIST)/leap
+ mkdir -p $(DIST)/leap
# if you find yourself puzzled becase the following files are not found in your
# virtualenv, make sure that you're installing the packages from wheels and not eggs.
mkdir -p $(DIST)/leap/soledad/client/_db
@@ -58,7 +58,6 @@ bundle_osx: bundle bundle_osx_helpers
cp $(DIST_VERSION)/lib/_scrypt.so $(OSX_CON)/
cp $(DIST_VERSION)/lib/bitmaskd.tac $(OSX_CON)/
cp -r $(DIST_VERSION)/lib/leap $(OSX_CON)/
- cp -r $(DIST_VERSION)/lib/pixelated_www $(OSX_CON)/
mv dist/Bitmask.app/Contents/MacOS/bitmask $(OSX_CON)/bitmask-app
cp pkg/osx/bitmask-wrapper $(OSX_CON)/bitmask
mkdir -p $(OSX_RES)/bitmask-helper
diff --git a/src/leap/bitmask/gui/app2.py b/src/leap/bitmask/gui/app2.py
new file mode 100644
index 00000000..13f369c4
--- /dev/null
+++ b/src/leap/bitmask/gui/app2.py
@@ -0,0 +1,144 @@
+# -*- coding: utf-8 -*-
+# app.py
+# Copyright (C) 2016 LEAP Encryption Acess Project
+#
+# 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/>.
+
+"""
+Main entrypoint for the Bitmask Qt GUI.
+It just launches a webview browser that runs the local web-ui served by bitmaskd
+when the web service is running.
+"""
+
+import os
+import platform
+import signal
+import sys
+import time
+import webbrowser
+
+from functools import partial
+from multiprocessing import Process
+
+from leap.bitmask.core.launcher import run_bitmaskd, pid
+from leap.common.config import get_path_prefix
+#from leap.bitmask.gui import app_rc
+
+import webview
+
+DEBUG = os.environ.get("DEBUG", False)
+
+BITMASK_URI = 'http://localhost:7070/'
+PIXELATED_URI = 'http://localhost:9090/'
+
+qApp = None
+bitmaskd = None
+browser = None
+
+
+class BrowserWindow(object):
+ """
+ A browser window using pywebview.
+
+ This BrowserWindow assumes that the backend is already running, since it is
+ going to look for the authtoken in the configuration folder.
+ """
+ def __init__(self, *args, **kw):
+ url = kw.pop('url', None)
+ first = False
+ if not url:
+ url = "http://localhost:7070"
+ path = os.path.join(get_path_prefix(), 'leap', 'authtoken')
+ waiting = 20
+ while not os.path.isfile(path):
+ if waiting == 0:
+ # If we arrive here, something really messed up happened,
+ # because touching the token file is one of the first
+ # things the backend does, and this BrowserWindow
+ # should be called *right after* launching the backend.
+ raise NoAuthToken(
+ 'No authentication token found!')
+ time.sleep(0.1)
+ waiting -= 1
+ token = open(path).read().strip()
+ url += '#' + token
+ first = True
+ self.url = url
+ self.closing = False
+
+ webview.create_window('Bitmask', self.url)
+
+
+ def loadPage(self, web_page):
+ self.load(url)
+
+ def shutdown(self, *args):
+ if self.closing:
+ return
+ self.closing = True
+ global bitmaskd
+ bitmaskd.join()
+ if os.path.isfile(pid):
+ with open(pid) as f:
+ pidno = int(f.read())
+ print('[bitmask] terminating bitmaskd...')
+ os.kill(pidno, signal.SIGTERM)
+ print('[bitmask] shutting down gui...')
+
+
+
+def launch_gui():
+ global bitmaskd
+ global browser
+
+ bitmaskd = Process(target=run_bitmaskd)
+ bitmaskd.start()
+
+ try:
+ browser = BrowserWindow(None)
+ except NoAuthToken as e:
+ print('ERROR: ' + e.message)
+ sys.exit(1)
+
+
+def start_app():
+ from leap.bitmask.util import STANDALONE
+ os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = '1'
+
+ # Allow the frozen binary in the bundle double as the cli entrypoint
+ # Why have only a user interface when you can have two?
+
+ if STANDALONE and len(sys.argv) > 1:
+ if sys.argv[1] == 'bitmask_helpers':
+ from leap.bitmask.vpn.helpers import main
+ return main()
+
+ from leap.bitmask.cli import bitmask_cli
+ return bitmask_cli.main()
+
+ prev_auth = os.path.join(get_path_prefix(), 'leap', 'authtoken')
+ try:
+ os.remove(prev_auth)
+ except OSError:
+ pass
+
+ launch_gui()
+
+
+class NoAuthToken(Exception):
+ pass
+
+
+if __name__ == "__main__":
+ start_app()