Browse Source

Support launching via Chrome native messaging

Johann Schmitz 7 months ago
parent
commit
88f1fef2ba
Signed by: Johann Schmitz <johann@j-schmitz.net> GPG Key ID: A084064277C501ED
4 changed files with 72 additions and 3 deletions
  1. 21
    2
      esgp/__main__.py
  2. 42
    0
      esgp/settings.py
  3. 4
    1
      esgp/ui.py
  4. 5
    0
      launch.sh

+ 21
- 2
esgp/__main__.py View File

@@ -14,7 +14,9 @@
14 14
 #
15 15
 # You should have received a copy of the GNU General Public License
16 16
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
+import json
17 18
 import logging
19
+import struct
18 20
 from argparse import ArgumentParser
19 21
 import daiquiri
20 22
 import sys
@@ -24,20 +26,37 @@ from PyQt5.QtWidgets import QApplication
24 26
 from esgp.config import Configuration
25 27
 from esgp.ui import MainWindow
26 28
 
29
+
30
+def _read_chrome_native_message():
31
+    logger = logging.getLogger(__file__)
32
+    text_length_bytes = sys.stdin.read(4)
33
+    text_length = struct.unpack("i", bytes(text_length_bytes, 'utf-8'))[0]
34
+    text_decoded = sys.stdin.read(text_length)
35
+    return json.loads(text_decoded)
36
+
37
+
27 38
 if __name__ == "__main__":
28 39
     parser = ArgumentParser()
29 40
     parser.add_argument('-d', '--domain')
30
-    parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Enable verbose logging (default: %(default)s)')
41
+    parser.add_argument('-v', '--verbose', action='store_true', default=False,
42
+                        help='Enable verbose logging (default: %(default)s)')
43
+    parser.add_argument('arg', nargs='?')
31 44
 
32 45
     args = parser.parse_args()
33 46
 
34 47
     daiquiri.setup(level=logging.DEBUG if args.verbose else logging.WARNING)
48
+    
49
+    url = None
50
+    
51
+    if (args.arg or "").startswith('chrome-extension://'):
52
+        # started from chrome extension
53
+        url = _read_chrome_native_message()['url']
35 54
 
36 55
     config = Configuration()
37 56
     config.read()
38 57
 
39 58
     app = QApplication(sys.argv)
40
-    main_window = MainWindow(config, args)
59
+    main_window = MainWindow(config, url, args)
41 60
     main_window.show()
42 61
 
43 62
     sys.exit(app.exec_())

+ 42
- 0
esgp/settings.py View File

@@ -13,12 +13,18 @@
13 13
 #
14 14
 # You should have received a copy of the GNU General Public License
15 15
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
+import json
17
+import os
18
+import sys
16 19
 
17 20
 from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant, QModelIndex, QRegExp
18 21
 from PyQt5.QtGui import QIntValidator, QRegExpValidator
19 22
 from PyQt5.QtWidgets import QDialog, QVBoxLayout, QFrame, QLabel, QTableView, QLineEdit, \
20 23
     QStyledItemDelegate, QPushButton, QComboBox, QHBoxLayout, QTableWidget, QAbstractItemView, QHeaderView
21 24
 
25
+import logging
26
+
27
+logger = logging.getLogger(__name__)
22 28
 
23 29
 class DomainSettingsTableModel(QAbstractTableModel):
24 30
     
@@ -128,10 +134,46 @@ class SettingsDialog(QDialog):
128 134
 
129 135
         layout.addWidget(self.build_domain_settings_ui())
130 136
         
137
+        layout.addLayout(self.build_chrome_extension_layout())
138
+        
131 139
         save_button = QPushButton('Save')
132 140
         save_button.clicked.connect(self.save_and_close)
133 141
         layout.addWidget(save_button)
134 142
         
143
+    def build_chrome_extension_layout(self):
144
+        l = QVBoxLayout()
145
+        
146
+        register_button = QPushButton('Register as a native messaging host in Chrome/Chromium')
147
+        register_button.clicked.connect(self.register_as_chrome_messaging_host)
148
+        l.addWidget(register_button)
149
+        return l
150
+        
151
+    def register_as_chrome_messaging_host(self):
152
+        for profile_directory in [ '~/.config/google-chrome/', '~/.config/chromium/' ]:
153
+            #NativeMessagingHosts/
154
+            directory = os.path.expanduser(profile_directory)
155
+            if not os.path.exists(directory):
156
+                logger.info("Skipping configuration in %s (not found)", directory)
157
+                continue
158
+            
159
+            path = os.path.join(directory, 'NativeMessagingHosts', 'de.ercpe.esgp.json')
160
+            
161
+            if not os.path.exists(os.path.dirname(path)):
162
+                os.mkdir(os.path.dirname(path))
163
+            
164
+            with open(path, 'w') as o:
165
+                cfg = {
166
+                    "name": "de.ercpe.esgp",
167
+                    "description": "eSGP",
168
+                    "path": sys.argv[0],
169
+                    "type": "stdio",
170
+                    "allowed_origins": [
171
+                        "chrome-extension://odhpmlfckigpfekmnaldaimknpdbodlo/"
172
+                    ]
173
+                }
174
+
175
+                o.write(json.dumps(cfg))
176
+
135 177
     def build_domain_settings_ui(self):
136 178
         # per-domain settings
137 179
         domain_settings_layout = QVBoxLayout()

+ 4
- 1
esgp/ui.py View File

@@ -32,7 +32,7 @@ logger = logging.getLogger(__name__)
32 32
 
33 33
 class MainWindow(QDialog):
34 34
     
35
-    def __init__(self, config, cmdargs, *args, **kwargs):
35
+    def __init__(self, config, url, cmdargs, *args, **kwargs):
36 36
         super(MainWindow, self).__init__(*args, **kwargs)
37 37
         
38 38
         self.config = config
@@ -49,6 +49,9 @@ class MainWindow(QDialog):
49 49
         self.build_ui()
50 50
         self.set_default_settings()
51 51
         self.show()
52
+        
53
+        if url:
54
+            self.domain_pasted(url)
52 55
 
53 56
     def build_ui(self):
54 57
         self.setWindowTitle('eSGP')

+ 5
- 0
launch.sh View File

@@ -0,0 +1,5 @@
1
+#!/bin/bash
2
+
3
+source ~/dev/.virtualenv/esgp/bin/activate
4
+cd $(dirname $0)
5
+cat /dev/stdin | python3 -m esgp $*