Daniel Brötzmann pushed to branch omemo_integration at gajim / gajim
Commits:
-
f4c51a34
by wurstsalat at 2022-10-18T00:45:00+02:00
12 changed files:
- gajim/data/gui/contact_info.ui
- gajim/data/gui/groupchat_details.ui
- + gajim/data/gui/omemo_trust_manager.ui
- + gajim/data/icons/hicolor/scalable/categories/qr-code-scan.svg
- gajim/data/style/gajim.css
- gajim/gtk/accounts.py
- gajim/gtk/builder.pyi
- gajim/gtk/chat_stack.py
- gajim/gtk/contact_info.py
- gajim/gtk/groupchat_details.py
- gajim/gtk/message_actions_box.py
- + gajim/gtk/omemo_trust_manager.py
Changes:
| 1 | 1 | <?xml version="1.0" encoding="UTF-8"?>
|
| 2 | -<!-- Generated with glade 3.38.2 -->
|
|
| 2 | +<!-- Generated with glade 3.40.0 -->
|
|
| 3 | 3 | <interface>
|
| 4 | 4 | <requires lib="gtk+" version="3.24"/>
|
| 5 | 5 | <!-- n-columns=2 n-rows=6 -->
|
| ... | ... | @@ -725,6 +725,39 @@ |
| 725 | 725 | <property name="position">1</property>
|
| 726 | 726 | </packing>
|
| 727 | 727 | </child>
|
| 728 | + <child>
|
|
| 729 | + <object class="GtkScrolledWindow" id="encryption_scrolled">
|
|
| 730 | + <property name="visible">True</property>
|
|
| 731 | + <property name="can-focus">True</property>
|
|
| 732 | + <property name="hscrollbar-policy">never</property>
|
|
| 733 | + <child>
|
|
| 734 | + <object class="GtkViewport">
|
|
| 735 | + <property name="visible">True</property>
|
|
| 736 | + <property name="can-focus">False</property>
|
|
| 737 | + <child>
|
|
| 738 | + <object class="GtkBox" id="encryption_box">
|
|
| 739 | + <property name="visible">True</property>
|
|
| 740 | + <property name="can-focus">False</property>
|
|
| 741 | + <property name="margin-start">36</property>
|
|
| 742 | + <property name="margin-end">36</property>
|
|
| 743 | + <property name="margin-top">36</property>
|
|
| 744 | + <property name="margin-bottom">36</property>
|
|
| 745 | + <property name="orientation">vertical</property>
|
|
| 746 | + <child>
|
|
| 747 | + <placeholder/>
|
|
| 748 | + </child>
|
|
| 749 | + </object>
|
|
| 750 | + </child>
|
|
| 751 | + </object>
|
|
| 752 | + </child>
|
|
| 753 | + </object>
|
|
| 754 | + <packing>
|
|
| 755 | + <property name="name">encryption-omemo</property>
|
|
| 756 | + <property name="title" translatable="yes">Encryption (OMEMO)</property>
|
|
| 757 | + <property name="icon-name">channel-secure-symbolic</property>
|
|
| 758 | + <property name="position">2</property>
|
|
| 759 | + </packing>
|
|
| 760 | + </child>
|
|
| 728 | 761 | <child>
|
| 729 | 762 | <object class="GtkBox" id="groups_page_box">
|
| 730 | 763 | <property name="visible">True</property>
|
| ... | ... | @@ -873,7 +906,7 @@ |
| 873 | 906 | <property name="name">groups</property>
|
| 874 | 907 | <property name="title" translatable="yes">Groups</property>
|
| 875 | 908 | <property name="icon-name">view-pin-symbolic</property>
|
| 876 | - <property name="position">2</property>
|
|
| 909 | + <property name="position">3</property>
|
|
| 877 | 910 | </packing>
|
| 878 | 911 | </child>
|
| 879 | 912 | <child>
|
| ... | ... | @@ -934,7 +967,7 @@ |
| 934 | 967 | <property name="name">notes</property>
|
| 935 | 968 | <property name="title" translatable="yes">Notes</property>
|
| 936 | 969 | <property name="icon-name">x-office-address-book-symbolic</property>
|
| 937 | - <property name="position">3</property>
|
|
| 970 | + <property name="position">4</property>
|
|
| 938 | 971 | </packing>
|
| 939 | 972 | </child>
|
| 940 | 973 | <child>
|
| ... | ... | @@ -1004,7 +1037,7 @@ |
| 1004 | 1037 | <property name="name">devices</property>
|
| 1005 | 1038 | <property name="title" translatable="yes">Devices</property>
|
| 1006 | 1039 | <property name="icon-name">computer-symbolic</property>
|
| 1007 | - <property name="position">4</property>
|
|
| 1040 | + <property name="position">5</property>
|
|
| 1008 | 1041 | </packing>
|
| 1009 | 1042 | </child>
|
| 1010 | 1043 | <style>
|
| 1 | 1 | <?xml version="1.0" encoding="UTF-8"?>
|
| 2 | -<!-- Generated with glade 3.38.2 -->
|
|
| 2 | +<!-- Generated with glade 3.40.0 -->
|
|
| 3 | 3 | <interface>
|
| 4 | 4 | <requires lib="gtk+" version="3.24"/>
|
| 5 | 5 | <!-- n-columns=2 n-rows=1 -->
|
| ... | ... | @@ -129,6 +129,39 @@ |
| 129 | 129 | <property name="position">1</property>
|
| 130 | 130 | </packing>
|
| 131 | 131 | </child>
|
| 132 | + <child>
|
|
| 133 | + <object class="GtkScrolledWindow" id="encryption_scrolled">
|
|
| 134 | + <property name="visible">True</property>
|
|
| 135 | + <property name="can-focus">True</property>
|
|
| 136 | + <property name="hscrollbar-policy">never</property>
|
|
| 137 | + <child>
|
|
| 138 | + <object class="GtkViewport">
|
|
| 139 | + <property name="visible">True</property>
|
|
| 140 | + <property name="can-focus">False</property>
|
|
| 141 | + <child>
|
|
| 142 | + <object class="GtkBox" id="encryption_box">
|
|
| 143 | + <property name="visible">True</property>
|
|
| 144 | + <property name="can-focus">False</property>
|
|
| 145 | + <property name="margin-start">36</property>
|
|
| 146 | + <property name="margin-end">36</property>
|
|
| 147 | + <property name="margin-top">36</property>
|
|
| 148 | + <property name="margin-bottom">36</property>
|
|
| 149 | + <property name="orientation">vertical</property>
|
|
| 150 | + <child>
|
|
| 151 | + <placeholder/>
|
|
| 152 | + </child>
|
|
| 153 | + </object>
|
|
| 154 | + </child>
|
|
| 155 | + </object>
|
|
| 156 | + </child>
|
|
| 157 | + </object>
|
|
| 158 | + <packing>
|
|
| 159 | + <property name="name">encryption-omemo</property>
|
|
| 160 | + <property name="title" translatable="yes">Encryption (OMEMO)</property>
|
|
| 161 | + <property name="icon-name">channel-secure-symbolic</property>
|
|
| 162 | + <property name="position">2</property>
|
|
| 163 | + </packing>
|
|
| 164 | + </child>
|
|
| 132 | 165 | <child>
|
| 133 | 166 | <object class="GtkBox" id="manage_box">
|
| 134 | 167 | <property name="visible">True</property>
|
| ... | ... | @@ -151,7 +184,7 @@ |
| 151 | 184 | <property name="name">manage</property>
|
| 152 | 185 | <property name="title" translatable="yes">Manage</property>
|
| 153 | 186 | <property name="icon-name">preferences-other-symbolic</property>
|
| 154 | - <property name="position">2</property>
|
|
| 187 | + <property name="position">3</property>
|
|
| 155 | 188 | </packing>
|
| 156 | 189 | </child>
|
| 157 | 190 | <child>
|
| ... | ... | @@ -170,7 +203,7 @@ |
| 170 | 203 | <property name="name">affiliations</property>
|
| 171 | 204 | <property name="title" translatable="yes">Affiliations</property>
|
| 172 | 205 | <property name="icon-name">system-users-symbolic</property>
|
| 173 | - <property name="position">3</property>
|
|
| 206 | + <property name="position">4</property>
|
|
| 174 | 207 | </packing>
|
| 175 | 208 | </child>
|
| 176 | 209 | <child>
|
| ... | ... | @@ -189,7 +222,7 @@ |
| 189 | 222 | <property name="name">outcasts</property>
|
| 190 | 223 | <property name="title" translatable="yes">Outcasts</property>
|
| 191 | 224 | <property name="icon-name">system-users-symbolic</property>
|
| 192 | - <property name="position">4</property>
|
|
| 225 | + <property name="position">5</property>
|
|
| 193 | 226 | </packing>
|
| 194 | 227 | </child>
|
| 195 | 228 | <child>
|
| ... | ... | @@ -205,7 +238,7 @@ |
| 205 | 238 | <property name="name">config</property>
|
| 206 | 239 | <property name="title" translatable="yes">Configuration</property>
|
| 207 | 240 | <property name="icon-name">document-properties-symbolic</property>
|
| 208 | - <property name="position">5</property>
|
|
| 241 | + <property name="position">6</property>
|
|
| 209 | 242 | </packing>
|
| 210 | 243 | </child>
|
| 211 | 244 | <style>
|
| 1 | +<?xml version="1.0" encoding="UTF-8"?>
|
|
| 2 | +<!-- Generated with glade 3.40.0 -->
|
|
| 3 | +<interface>
|
|
| 4 | + <requires lib="gtk+" version="3.24"/>
|
|
| 5 | + <object class="GtkPopover" id="search_popover">
|
|
| 6 | + <property name="can-focus">False</property>
|
|
| 7 | + <child>
|
|
| 8 | + <object class="GtkSearchEntry" id="search">
|
|
| 9 | + <property name="visible">True</property>
|
|
| 10 | + <property name="can-focus">True</property>
|
|
| 11 | + <property name="caps-lock-warning">False</property>
|
|
| 12 | + <property name="primary-icon-name">edit-find-symbolic</property>
|
|
| 13 | + <property name="primary-icon-activatable">False</property>
|
|
| 14 | + <property name="primary-icon-sensitive">False</property>
|
|
| 15 | + <signal name="search-changed" handler="_on_search_changed" swapped="no"/>
|
|
| 16 | + </object>
|
|
| 17 | + </child>
|
|
| 18 | + </object>
|
|
| 19 | + <object class="GtkPopover" id="qr_code_popover">
|
|
| 20 | + <property name="can-focus">False</property>
|
|
| 21 | + <property name="relative-to">qr_menu_button</property>
|
|
| 22 | + <property name="constrain-to">none</property>
|
|
| 23 | + <child>
|
|
| 24 | + <object class="GtkBox">
|
|
| 25 | + <property name="visible">True</property>
|
|
| 26 | + <property name="can-focus">False</property>
|
|
| 27 | + <property name="orientation">vertical</property>
|
|
| 28 | + <property name="spacing">12</property>
|
|
| 29 | + <child>
|
|
| 30 | + <object class="GtkLabel">
|
|
| 31 | + <property name="visible">True</property>
|
|
| 32 | + <property name="can-focus">False</property>
|
|
| 33 | + <property name="label" translatable="yes">This Device</property>
|
|
| 34 | + <style>
|
|
| 35 | + <class name="bold16"/>
|
|
| 36 | + </style>
|
|
| 37 | + </object>
|
|
| 38 | + <packing>
|
|
| 39 | + <property name="expand">False</property>
|
|
| 40 | + <property name="fill">True</property>
|
|
| 41 | + <property name="position">0</property>
|
|
| 42 | + </packing>
|
|
| 43 | + </child>
|
|
| 44 | + <child>
|
|
| 45 | + <object class="GtkLabel" id="comparing_instructions">
|
|
| 46 | + <property name="visible">True</property>
|
|
| 47 | + <property name="can-focus">False</property>
|
|
| 48 | + <property name="margin-bottom">13</property>
|
|
| 49 | + <property name="wrap">True</property>
|
|
| 50 | + <property name="max-width-chars">42</property>
|
|
| 51 | + <property name="xalign">0</property>
|
|
| 52 | + <style>
|
|
| 53 | + <class name="dim-label"/>
|
|
| 54 | + </style>
|
|
| 55 | + </object>
|
|
| 56 | + <packing>
|
|
| 57 | + <property name="expand">False</property>
|
|
| 58 | + <property name="fill">True</property>
|
|
| 59 | + <property name="position">1</property>
|
|
| 60 | + </packing>
|
|
| 61 | + </child>
|
|
| 62 | + <child>
|
|
| 63 | + <object class="GtkLabel" id="our_fingerprint_2">
|
|
| 64 | + <property name="visible">True</property>
|
|
| 65 | + <property name="can-focus">False</property>
|
|
| 66 | + <property name="selectable">True</property>
|
|
| 67 | + <style>
|
|
| 68 | + <class name="fingerprint"/>
|
|
| 69 | + </style>
|
|
| 70 | + </object>
|
|
| 71 | + <packing>
|
|
| 72 | + <property name="expand">False</property>
|
|
| 73 | + <property name="fill">True</property>
|
|
| 74 | + <property name="position">2</property>
|
|
| 75 | + </packing>
|
|
| 76 | + </child>
|
|
| 77 | + <child>
|
|
| 78 | + <object class="GtkImage" id="qr_code_image">
|
|
| 79 | + <property name="visible">True</property>
|
|
| 80 | + <property name="can-focus">False</property>
|
|
| 81 | + <property name="icon_size">6</property>
|
|
| 82 | + </object>
|
|
| 83 | + <packing>
|
|
| 84 | + <property name="expand">False</property>
|
|
| 85 | + <property name="fill">True</property>
|
|
| 86 | + <property name="position">3</property>
|
|
| 87 | + </packing>
|
|
| 88 | + </child>
|
|
| 89 | + <child>
|
|
| 90 | + <object class="GtkLabel" id="qr_dependency_missing">
|
|
| 91 | + <property name="visible">True</property>
|
|
| 92 | + <property name="can-focus">False</property>
|
|
| 93 | + <property name="label" translatable="yes">For verification via QR-Code you have to install <tt>python-qrcode</tt>.</property>
|
|
| 94 | + <property name="use-markup">True</property>
|
|
| 95 | + <property name="wrap">True</property>
|
|
| 96 | + <property name="max-width-chars">42</property>
|
|
| 97 | + <property name="xalign">0</property>
|
|
| 98 | + <style>
|
|
| 99 | + <class name="dim-label"/>
|
|
| 100 | + </style>
|
|
| 101 | + </object>
|
|
| 102 | + <packing>
|
|
| 103 | + <property name="expand">False</property>
|
|
| 104 | + <property name="fill">True</property>
|
|
| 105 | + <property name="position">4</property>
|
|
| 106 | + </packing>
|
|
| 107 | + </child>
|
|
| 108 | + <style>
|
|
| 109 | + <class name="padding-18"/>
|
|
| 110 | + </style>
|
|
| 111 | + </object>
|
|
| 112 | + </child>
|
|
| 113 | + </object>
|
|
| 114 | + <object class="GtkStack" id="stack">
|
|
| 115 | + <property name="width-request">400</property>
|
|
| 116 | + <property name="visible">True</property>
|
|
| 117 | + <property name="can-focus">False</property>
|
|
| 118 | + <property name="transition-type">crossfade</property>
|
|
| 119 | + <property name="interpolate-size">True</property>
|
|
| 120 | + <child>
|
|
| 121 | + <object class="GtkBox">
|
|
| 122 | + <property name="visible">True</property>
|
|
| 123 | + <property name="can-focus">False</property>
|
|
| 124 | + <property name="orientation">vertical</property>
|
|
| 125 | + <property name="spacing">12</property>
|
|
| 126 | + <child>
|
|
| 127 | + <object class="GtkLabel">
|
|
| 128 | + <property name="visible">True</property>
|
|
| 129 | + <property name="can-focus">False</property>
|
|
| 130 | + <property name="label" translatable="yes">This Device</property>
|
|
| 131 | + <property name="xalign">0</property>
|
|
| 132 | + <style>
|
|
| 133 | + <class name="bold"/>
|
|
| 134 | + </style>
|
|
| 135 | + </object>
|
|
| 136 | + <packing>
|
|
| 137 | + <property name="expand">False</property>
|
|
| 138 | + <property name="fill">True</property>
|
|
| 139 | + <property name="position">0</property>
|
|
| 140 | + </packing>
|
|
| 141 | + </child>
|
|
| 142 | + <child>
|
|
| 143 | + <object class="GtkListBox">
|
|
| 144 | + <property name="visible">True</property>
|
|
| 145 | + <property name="can-focus">False</property>
|
|
| 146 | + <property name="selection-mode">none</property>
|
|
| 147 | + <child>
|
|
| 148 | + <object class="GtkListBoxRow">
|
|
| 149 | + <property name="visible">True</property>
|
|
| 150 | + <property name="can-focus">True</property>
|
|
| 151 | + <property name="selectable">False</property>
|
|
| 152 | + <child>
|
|
| 153 | + <object class="GtkBox">
|
|
| 154 | + <property name="visible">True</property>
|
|
| 155 | + <property name="can-focus">False</property>
|
|
| 156 | + <property name="spacing">12</property>
|
|
| 157 | + <child>
|
|
| 158 | + <object class="GtkBox">
|
|
| 159 | + <property name="visible">True</property>
|
|
| 160 | + <property name="can-focus">False</property>
|
|
| 161 | + <property name="orientation">vertical</property>
|
|
| 162 | + <property name="spacing">3</property>
|
|
| 163 | + <child>
|
|
| 164 | + <object class="GtkLabel">
|
|
| 165 | + <property name="visible">True</property>
|
|
| 166 | + <property name="can-focus">False</property>
|
|
| 167 | + <property name="label" translatable="yes">Fingerprint for this Device</property>
|
|
| 168 | + <property name="xalign">0</property>
|
|
| 169 | + </object>
|
|
| 170 | + <packing>
|
|
| 171 | + <property name="expand">False</property>
|
|
| 172 | + <property name="fill">True</property>
|
|
| 173 | + <property name="position">0</property>
|
|
| 174 | + </packing>
|
|
| 175 | + </child>
|
|
| 176 | + <child>
|
|
| 177 | + <object class="GtkLabel" id="our_fingerprint_1">
|
|
| 178 | + <property name="visible">True</property>
|
|
| 179 | + <property name="can-focus">False</property>
|
|
| 180 | + <property name="selectable">True</property>
|
|
| 181 | + <property name="xalign">0</property>
|
|
| 182 | + <style>
|
|
| 183 | + <class name="fingerprint"/>
|
|
| 184 | + </style>
|
|
| 185 | + </object>
|
|
| 186 | + <packing>
|
|
| 187 | + <property name="expand">False</property>
|
|
| 188 | + <property name="fill">True</property>
|
|
| 189 | + <property name="position">1</property>
|
|
| 190 | + </packing>
|
|
| 191 | + </child>
|
|
| 192 | + </object>
|
|
| 193 | + <packing>
|
|
| 194 | + <property name="expand">False</property>
|
|
| 195 | + <property name="fill">True</property>
|
|
| 196 | + <property name="position">0</property>
|
|
| 197 | + </packing>
|
|
| 198 | + </child>
|
|
| 199 | + <child>
|
|
| 200 | + <object class="GtkMenuButton" id="qr_menu_button">
|
|
| 201 | + <property name="visible">True</property>
|
|
| 202 | + <property name="can-focus">True</property>
|
|
| 203 | + <property name="receives-default">True</property>
|
|
| 204 | + <property name="tooltip-text" translatable="yes">Scan QR Code</property>
|
|
| 205 | + <property name="halign">end</property>
|
|
| 206 | + <property name="valign">center</property>
|
|
| 207 | + <property name="direction">up</property>
|
|
| 208 | + <property name="popover">qr_code_popover</property>
|
|
| 209 | + <child>
|
|
| 210 | + <object class="GtkImage">
|
|
| 211 | + <property name="visible">True</property>
|
|
| 212 | + <property name="can-focus">False</property>
|
|
| 213 | + <property name="icon-name">qr-code-scan</property>
|
|
| 214 | + </object>
|
|
| 215 | + </child>
|
|
| 216 | + <style>
|
|
| 217 | + <class name="image-button"/>
|
|
| 218 | + </style>
|
|
| 219 | + </object>
|
|
| 220 | + <packing>
|
|
| 221 | + <property name="expand">False</property>
|
|
| 222 | + <property name="fill">True</property>
|
|
| 223 | + <property name="pack-type">end</property>
|
|
| 224 | + <property name="position">1</property>
|
|
| 225 | + </packing>
|
|
| 226 | + </child>
|
|
| 227 | + <child>
|
|
| 228 | + <object class="GtkButton" id="manage_trust_button">
|
|
| 229 | + <property name="can-focus">True</property>
|
|
| 230 | + <property name="receives-default">True</property>
|
|
| 231 | + <property name="no-show-all">True</property>
|
|
| 232 | + <property name="tooltip-text" translatable="yes">Manage your Devices…</property>
|
|
| 233 | + <property name="valign">center</property>
|
|
| 234 | + <signal name="clicked" handler="_on_manage_trust_clicked" swapped="no"/>
|
|
| 235 | + <child>
|
|
| 236 | + <object class="GtkImage">
|
|
| 237 | + <property name="visible">True</property>
|
|
| 238 | + <property name="can-focus">False</property>
|
|
| 239 | + <property name="icon-name">channel-secure-symbolic</property>
|
|
| 240 | + </object>
|
|
| 241 | + </child>
|
|
| 242 | + <style>
|
|
| 243 | + <class name="image-button"/>
|
|
| 244 | + </style>
|
|
| 245 | + </object>
|
|
| 246 | + <packing>
|
|
| 247 | + <property name="expand">False</property>
|
|
| 248 | + <property name="fill">True</property>
|
|
| 249 | + <property name="pack-type">end</property>
|
|
| 250 | + <property name="position">2</property>
|
|
| 251 | + </packing>
|
|
| 252 | + </child>
|
|
| 253 | + </object>
|
|
| 254 | + </child>
|
|
| 255 | + </object>
|
|
| 256 | + </child>
|
|
| 257 | + <style>
|
|
| 258 | + <class name="settings-box"/>
|
|
| 259 | + </style>
|
|
| 260 | + </object>
|
|
| 261 | + <packing>
|
|
| 262 | + <property name="expand">False</property>
|
|
| 263 | + <property name="fill">True</property>
|
|
| 264 | + <property name="position">1</property>
|
|
| 265 | + </packing>
|
|
| 266 | + </child>
|
|
| 267 | + <child>
|
|
| 268 | + <object class="GtkLabel" id="list_heading">
|
|
| 269 | + <property name="visible">True</property>
|
|
| 270 | + <property name="can-focus">False</property>
|
|
| 271 | + <property name="margin-top">12</property>
|
|
| 272 | + <property name="wrap">True</property>
|
|
| 273 | + <property name="max-width-chars">42</property>
|
|
| 274 | + <property name="xalign">0</property>
|
|
| 275 | + <style>
|
|
| 276 | + <class name="bold"/>
|
|
| 277 | + </style>
|
|
| 278 | + </object>
|
|
| 279 | + <packing>
|
|
| 280 | + <property name="expand">False</property>
|
|
| 281 | + <property name="fill">True</property>
|
|
| 282 | + <property name="position">2</property>
|
|
| 283 | + </packing>
|
|
| 284 | + </child>
|
|
| 285 | + <child>
|
|
| 286 | + <object class="GtkBox" id="list_heading_box">
|
|
| 287 | + <property name="visible">True</property>
|
|
| 288 | + <property name="can-focus">False</property>
|
|
| 289 | + <property name="spacing">12</property>
|
|
| 290 | + <child>
|
|
| 291 | + <object class="GtkSwitch" id="show_inactive_switch">
|
|
| 292 | + <property name="visible">True</property>
|
|
| 293 | + <property name="can-focus">True</property>
|
|
| 294 | + <property name="valign">center</property>
|
|
| 295 | + <signal name="notify::active" handler="_on_show_inactive" swapped="no"/>
|
|
| 296 | + </object>
|
|
| 297 | + <packing>
|
|
| 298 | + <property name="expand">False</property>
|
|
| 299 | + <property name="fill">True</property>
|
|
| 300 | + <property name="pack-type">end</property>
|
|
| 301 | + <property name="position">0</property>
|
|
| 302 | + </packing>
|
|
| 303 | + </child>
|
|
| 304 | + <child>
|
|
| 305 | + <object class="GtkLabel">
|
|
| 306 | + <property name="visible">True</property>
|
|
| 307 | + <property name="can-focus">False</property>
|
|
| 308 | + <property name="label" translatable="yes">Show Inactive Devices</property>
|
|
| 309 | + </object>
|
|
| 310 | + <packing>
|
|
| 311 | + <property name="expand">False</property>
|
|
| 312 | + <property name="fill">True</property>
|
|
| 313 | + <property name="pack-type">end</property>
|
|
| 314 | + <property name="position">1</property>
|
|
| 315 | + </packing>
|
|
| 316 | + </child>
|
|
| 317 | + <child>
|
|
| 318 | + <object class="GtkMenuButton" id="search_button">
|
|
| 319 | + <property name="can-focus">True</property>
|
|
| 320 | + <property name="receives-default">True</property>
|
|
| 321 | + <property name="no-show-all">True</property>
|
|
| 322 | + <property name="tooltip-text" translatable="yes">Search…</property>
|
|
| 323 | + <property name="halign">start</property>
|
|
| 324 | + <property name="valign">center</property>
|
|
| 325 | + <property name="popover">search_popover</property>
|
|
| 326 | + <child>
|
|
| 327 | + <object class="GtkImage">
|
|
| 328 | + <property name="visible">True</property>
|
|
| 329 | + <property name="can-focus">False</property>
|
|
| 330 | + <property name="icon-name">edit-find-symbolic</property>
|
|
| 331 | + </object>
|
|
| 332 | + </child>
|
|
| 333 | + </object>
|
|
| 334 | + <packing>
|
|
| 335 | + <property name="expand">False</property>
|
|
| 336 | + <property name="fill">True</property>
|
|
| 337 | + <property name="position">2</property>
|
|
| 338 | + </packing>
|
|
| 339 | + </child>
|
|
| 340 | + </object>
|
|
| 341 | + <packing>
|
|
| 342 | + <property name="expand">False</property>
|
|
| 343 | + <property name="fill">True</property>
|
|
| 344 | + <property name="position">3</property>
|
|
| 345 | + </packing>
|
|
| 346 | + </child>
|
|
| 347 | + <child>
|
|
| 348 | + <object class="GtkListBox" id="list">
|
|
| 349 | + <property name="visible">True</property>
|
|
| 350 | + <property name="can-focus">False</property>
|
|
| 351 | + <property name="selection-mode">none</property>
|
|
| 352 | + </object>
|
|
| 353 | + <packing>
|
|
| 354 | + <property name="expand">True</property>
|
|
| 355 | + <property name="fill">True</property>
|
|
| 356 | + <property name="position">4</property>
|
|
| 357 | + </packing>
|
|
| 358 | + </child>
|
|
| 359 | + <child>
|
|
| 360 | + <object class="GtkButton" id="clear_devices_button">
|
|
| 361 | + <property name="label" translatable="yes">Clear Devices…</property>
|
|
| 362 | + <property name="can-focus">True</property>
|
|
| 363 | + <property name="receives-default">True</property>
|
|
| 364 | + <property name="no-show-all">True</property>
|
|
| 365 | + <property name="halign">start</property>
|
|
| 366 | + <signal name="clicked" handler="_on_clear_devices_clicked" swapped="no"/>
|
|
| 367 | + <style>
|
|
| 368 | + <class name="destructive-action"/>
|
|
| 369 | + </style>
|
|
| 370 | + </object>
|
|
| 371 | + <packing>
|
|
| 372 | + <property name="expand">False</property>
|
|
| 373 | + <property name="fill">True</property>
|
|
| 374 | + <property name="position">5</property>
|
|
| 375 | + </packing>
|
|
| 376 | + </child>
|
|
| 377 | + <style>
|
|
| 378 | + <class name="omemo-trust-manager"/>
|
|
| 379 | + </style>
|
|
| 380 | + </object>
|
|
| 381 | + <packing>
|
|
| 382 | + <property name="name">manage-keys</property>
|
|
| 383 | + </packing>
|
|
| 384 | + </child>
|
|
| 385 | + <child>
|
|
| 386 | + <object class="GtkBox">
|
|
| 387 | + <property name="visible">True</property>
|
|
| 388 | + <property name="can-focus">False</property>
|
|
| 389 | + <property name="halign">center</property>
|
|
| 390 | + <property name="valign">center</property>
|
|
| 391 | + <property name="orientation">vertical</property>
|
|
| 392 | + <child>
|
|
| 393 | + <object class="GtkLabel">
|
|
| 394 | + <property name="visible">True</property>
|
|
| 395 | + <property name="can-focus">False</property>
|
|
| 396 | + <property name="label" translatable="yes">Account is not connected.</property>
|
|
| 397 | + <property name="wrap">True</property>
|
|
| 398 | + <property name="max-width-chars">42</property>
|
|
| 399 | + <style>
|
|
| 400 | + <class name="dim-label"/>
|
|
| 401 | + </style>
|
|
| 402 | + </object>
|
|
| 403 | + <packing>
|
|
| 404 | + <property name="expand">False</property>
|
|
| 405 | + <property name="fill">True</property>
|
|
| 406 | + <property name="position">0</property>
|
|
| 407 | + </packing>
|
|
| 408 | + </child>
|
|
| 409 | + </object>
|
|
| 410 | + <packing>
|
|
| 411 | + <property name="name">no-connection</property>
|
|
| 412 | + <property name="position">1</property>
|
|
| 413 | + </packing>
|
|
| 414 | + </child>
|
|
| 415 | + </object>
|
|
| 416 | +</interface> |
| 1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
| 2 | +<svg
|
|
| 3 | + width="296"
|
|
| 4 | + height="296"
|
|
| 5 | + viewBox="0 0 296 296"
|
|
| 6 | + version="1.1"
|
|
| 7 | + id="svg879"
|
|
| 8 | + sodipodi:docname="qr-code-scan.svg"
|
|
| 9 | + xml:space="preserve"
|
|
| 10 | + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)"
|
|
| 11 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
| 12 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
| 13 | + xmlns="http://www.w3.org/2000/svg"
|
|
| 14 | + xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
|
| 15 | + id="namedview881"
|
|
| 16 | + pagecolor="#ffffff"
|
|
| 17 | + bordercolor="#666666"
|
|
| 18 | + borderopacity="1.0"
|
|
| 19 | + inkscape:showpageshadow="2"
|
|
| 20 | + inkscape:pageopacity="0.0"
|
|
| 21 | + inkscape:pagecheckerboard="0"
|
|
| 22 | + inkscape:deskcolor="#d1d1d1"
|
|
| 23 | + showgrid="false"
|
|
| 24 | + inkscape:zoom="1.1820013"
|
|
| 25 | + inkscape:cx="-30.033808"
|
|
| 26 | + inkscape:cy="205.58353"
|
|
| 27 | + inkscape:window-width="1920"
|
|
| 28 | + inkscape:window-height="998"
|
|
| 29 | + inkscape:window-x="0"
|
|
| 30 | + inkscape:window-y="0"
|
|
| 31 | + inkscape:window-maximized="1"
|
|
| 32 | + inkscape:current-layer="svg879" /><defs
|
|
| 33 | + id="defs5"><rect
|
|
| 34 | + id="p"
|
|
| 35 | + width="8"
|
|
| 36 | + height="8" /></defs><g
|
|
| 37 | + id="g3488"
|
|
| 38 | + transform="matrix(1.1697246,0,0,1.1697246,-27.551074,-25.261865)"><path
|
|
| 39 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 40 | + d="M 251.48889,66.946387 V 46.712014 H 231.25452 211.02015 V 36.475802 26.23959 h 21.16314 c 22.41235,0 24.39388,0.156166 28.55025,2.250069 3.06508,1.544132 6.94528,5.251442 8.51507,8.135659 2.59204,4.762428 2.71271,6.062675 2.71271,29.230841 V 87.18076 h -10.23621 -10.23622 z"
|
|
| 41 | + id="path3464" /><path
|
|
| 42 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 43 | + d="m 28.196638,66.017616 c 0,-22.412343 0.156166,-24.393876 2.250069,-28.550247 1.544132,-3.065083 5.251442,-6.945286 8.135659,-8.515074 4.762428,-2.592038 6.062675,-2.712705 29.230841,-2.712705 H 89.137808 V 36.475802 46.712014 H 68.903435 48.669062 V 66.946387 87.18076 H 38.43285 28.196638 Z"
|
|
| 44 | + id="path3462" /><path
|
|
| 45 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 46 | + d="M 170.5514,97.175398 V 66.701287 l 30.35156,0.12255 30.35156,0.12255 0.12255,30.351559 0.12255,30.351564 H 201.02551 170.5514 Z m 40.46875,0.241574 V 87.18076 h -10.23621 -10.23622 v 9.918809 c 0,5.455351 0.14283,10.061641 0.31741,10.236211 0.17457,0.17457 4.78086,0.3174 10.23621,0.3174 h 9.91881 z"
|
|
| 47 | + id="path3460" /><path
|
|
| 48 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 49 | + d="M 140.08082,107.41513 V 87.18076 h 9.99816 9.99816 v 20.23437 20.23438 h -9.99816 -9.99816 z"
|
|
| 50 | + id="path3458" /><path
|
|
| 51 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 52 | + d="m 68.780885,97.297946 0.12255,-30.351559 30.351559,-0.12255 30.351556,-0.12255 V 97.175398 127.64951 H 99.132446 68.658335 Z m 40.719795,0 0.12849,-10.117186 H 99.38349 89.137808 v 10.245682 10.245678 l 10.117186,-0.12849 10.117186,-0.1285 z"
|
|
| 53 | + id="path3456" /><path
|
|
| 54 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 55 | + d="m 68.665384,148.12193 v -9.99816 h 10.236212 10.236212 v 9.99816 9.99816 H 78.901596 68.665384 Z"
|
|
| 56 | + id="path3454" /><path
|
|
| 57 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 58 | + d="m 139.97126,168.47533 -0.12849,-10.11719 -10.11719,-0.12849 -30.662081,-0.28013 v -9.98869 -9.98869 l 40.779271,0.15163 h 20.23437 v 20.23437 20.23437 h -9.98869 -9.98869 z"
|
|
| 59 | + id="path3452"
|
|
| 60 | + sodipodi:nodetypes="ccccccccccccc" /><path
|
|
| 61 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 62 | + d="m 211.02015,193.82781 v -15.2353 h -10.23621 -10.23622 v 15.2353 15.23529 h 10.23622 10.23621 z"
|
|
| 63 | + id="path3474" /><path
|
|
| 64 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 65 | + d="m 140.08082,209.0631 v -20.47242 h 15.23529 15.23529 v -4.99908 -4.99909 h 9.99816 9.99816 V 168.3563 158.12009 h -9.99816 -9.99816 v -9.99816 -9.99816 h 9.99816 9.99816 v 9.99816 9.99816 h 10.23622 10.23621 v -9.99816 -9.99816 h 10.23621 10.23621 v 9.99816 9.99816 h -10.23621 -10.23621 v 10.23621 10.23621 h 10.23621 10.23621 v 15.2353 15.23529 h -10.23621 -10.23621 v 10.24568 10.24568 l -10.11719,-0.12849 -10.11718,-0.1285 -0.1285,-10.11718 -0.1285,-10.11719 h -15.22582 -15.22582 v 10.23621 10.23621 h -9.99816 -9.99816 z"
|
|
| 66 | + id="path3450" /><path
|
|
| 67 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 68 | + d="m 68.982786,229.21812 c -0.174571,-0.17457 -0.317402,-13.88633 -0.317402,-30.47058 v -30.15319 h 30.470585 30.470581 v 30.47059 30.47058 H 99.453372 c -16.584254,0 -30.296015,-0.14283 -30.470586,-0.3174 z m 40.517894,-30.27221 -0.1285,-10.11718 -10.117186,-0.1285 -10.117186,-0.12849 v 10.24568 10.24568 h 10.245682 10.24568 z"
|
|
| 69 | + id="path3448" /><path
|
|
| 70 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 71 | + d="m 211.02015,259.76806 v -10.23621 h 20.23437 20.23437 V 229.29747 209.0631 h 10.23622 10.23621 v 21.3246 c 0,23.16817 -0.12067,24.46841 -2.71271,29.23084 -1.56979,2.88422 -5.44999,6.59153 -8.51507,8.13566 -4.15637,2.0939 -6.1379,2.25007 -28.55025,2.25007 h -21.16314 z"
|
|
| 72 | + id="path3446" /><path
|
|
| 73 | + style="fill:#000000;stroke-width:0.476103"
|
|
| 74 | + d="m 43.551277,269.26862 c -1.374571,-0.37014 -3.39419,-1.12956 -4.488044,-1.6876 -2.760243,-1.40817 -6.658458,-5.21488 -8.15389,-7.96248 -2.592038,-4.76243 -2.712705,-6.06267 -2.712705,-29.23084 V 209.0631 H 38.43285 48.669062 v 20.23437 20.23438 h 20.234373 20.234373 v 10.23621 10.23621 l -21.543656,-0.0313 c -16.989841,-0.0247 -22.071931,-0.17358 -24.042875,-0.70431 z"
|
|
| 75 | + id="path3346" /></g></svg> |
| ... | ... | @@ -577,7 +577,7 @@ list.settings > row:not(:last-child) { |
| 577 | 577 | }
|
| 578 | 578 | list.settings row { min-height: 52px; }
|
| 579 | 579 | list.settings > row > box {
|
| 580 | - margin: 6px 18px;
|
|
| 580 | + margin: 10px 20px 10px 10px;
|
|
| 581 | 581 | }
|
| 582 | 582 | |
| 583 | 583 | /* Settings Window */
|
| ... | ... | @@ -625,7 +625,7 @@ #SendFileDialog grid list > row { padding: 10px 20px 10px 10px; } |
| 625 | 625 | /* Accounts Window */
|
| 626 | 626 | .accounts-menu { border-right: 1px solid; border-color: @borders;}
|
| 627 | 627 | .accounts-settings-border {border: 1px solid; border-color: @borders;}
|
| 628 | -.accounts-settings stack > box { margin:30px; }
|
|
| 628 | +.accounts-settings stack > box.settings-page { margin:30px; }
|
|
| 629 | 629 | .accounts-label-row {
|
| 630 | 630 | padding-top: 10px;
|
| 631 | 631 | padding-bottom: 10px;
|
| ... | ... | @@ -766,6 +766,8 @@ .large-header { |
| 766 | 766 | font-size: 1.75rem;
|
| 767 | 767 | font-weight: bold;
|
| 768 | 768 | }
|
| 769 | +.monospace { font-family: monospace; }
|
|
| 770 | + |
|
| 769 | 771 | .insensitive-fg-color {color: @insensitive_fg_color;}
|
| 770 | 772 | |
| 771 | 773 | /* Padding/Margins */
|
| ... | ... | @@ -799,6 +801,28 @@ .selected-color { color: @theme_selected_bg_color; } |
| 799 | 801 | .encrypted-color { color: rgb(75, 181, 67); }
|
| 800 | 802 | .unencrypted-color { color: @error_color; }
|
| 801 | 803 | |
| 804 | +/* OMEMO */
|
|
| 805 | +.fingerprint {
|
|
| 806 | + color: @insensitive_fg_color;
|
|
| 807 | + font-family: monospace;
|
|
| 808 | + font-size: 90%;
|
|
| 809 | +}
|
|
| 810 | +.omemo-inactive-color { color: @insensitive_fg_color; }
|
|
| 811 | + |
|
| 812 | +.omemo-trust-manager list row {
|
|
| 813 | + border-bottom: 1px solid;
|
|
| 814 | + border-color: @unfocused_borders;
|
|
| 815 | + padding: 10px 20px 10px 10px;
|
|
| 816 | +}
|
|
| 817 | +.omemo-trust-manager list row:last-child { border-bottom: 0px}
|
|
| 818 | +.omemo-trust-manager list {
|
|
| 819 | + border: 1px solid;
|
|
| 820 | + border-color:@unfocused_borders;
|
|
| 821 | +}
|
|
| 822 | +.omemo-trust-manager list > row { outline: none; }
|
|
| 823 | + |
|
| 824 | +.omemo-trust-popover row { padding: 10px 15px 10px 10px; }
|
|
| 825 | + |
|
| 802 | 826 | /*Receipts*/
|
| 803 | 827 | .receipt-received-color { color: rgb(75, 181, 67); }
|
| 804 | 828 |
| ... | ... | @@ -40,6 +40,7 @@ |
| 40 | 40 | from .const import Setting
|
| 41 | 41 | from .const import SettingKind
|
| 42 | 42 | from .const import SettingType
|
| 43 | +from .omemo_trust_manager import OMEMOTrustManager
|
|
| 43 | 44 | from .settings import SettingsDialog
|
| 44 | 45 | from .settings import SettingsBox
|
| 45 | 46 | from .settings import PopoverSetting
|
| ... | ... | @@ -317,6 +318,7 @@ def __init__(self, account: str) -> None: |
| 317 | 318 | self.add(BackMenuItem())
|
| 318 | 319 | self.add(PageMenuItem('general', _('General')))
|
| 319 | 320 | self.add(PageMenuItem('privacy', _('Privacy')))
|
| 321 | + self.add(PageMenuItem('encryption', _('Encryption (OMEMO)')))
|
|
| 320 | 322 | self.add(PageMenuItem('connection', _('Connection')))
|
| 321 | 323 | self.add(PageMenuItem('advanced', _('Advanced')))
|
| 322 | 324 | self.add(RemoveMenuItem())
|
| ... | ... | @@ -411,6 +413,8 @@ def __init__(self, name: str, label: str) -> None: |
| 411 | 413 | icon = 'preferences-system-symbolic'
|
| 412 | 414 | elif name == 'privacy':
|
| 413 | 415 | icon = 'preferences-system-privacy-symbolic'
|
| 416 | + elif name == 'encryption':
|
|
| 417 | + icon = 'channel-secure-symbolic'
|
|
| 414 | 418 | elif name == 'connection':
|
| 415 | 419 | icon = 'preferences-system-network-symbolic'
|
| 416 | 420 | elif name == 'advanced':
|
| ... | ... | @@ -436,8 +440,9 @@ def __init__(self, |
| 436 | 440 | self._settings = settings
|
| 437 | 441 | |
| 438 | 442 | self._settings.add_page(GeneralPage(account))
|
| 439 | - self._settings.add_page(ConnectionPage(account))
|
|
| 440 | 443 | self._settings.add_page(PrivacyPage(account))
|
| 444 | + self._settings.add_page(EncryptionPage(account))
|
|
| 445 | + self._settings.add_page(ConnectionPage(account))
|
|
| 441 | 446 | self._settings.add_page(AdvancedPage(account))
|
| 442 | 447 | |
| 443 | 448 | self._account_row = AccountRow(account)
|
| ... | ... | @@ -616,6 +621,7 @@ def __init__(self, account: str, settings: list[Setting]) -> None: |
| 616 | 621 | Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, spacing=12)
|
| 617 | 622 | self.set_valign(Gtk.Align.START)
|
| 618 | 623 | self.set_vexpand(True)
|
| 624 | + self.get_style_context().add_class('settings-page')
|
|
| 619 | 625 | self.account = account
|
| 620 | 626 | |
| 621 | 627 | self.listbox = SettingsBox(account)
|
| ... | ... | @@ -891,6 +897,40 @@ def _reset_send_read_marker(self, button: Gtk.Button) -> None: |
| 891 | 897 | 'send_marker', None, context='private')
|
| 892 | 898 | |
| 893 | 899 | |
| 900 | +class EncryptionPage(GenericSettingPage):
|
|
| 901 | + |
|
| 902 | + name = 'encryption'
|
|
| 903 | + |
|
| 904 | + def __init__(self, account: str) -> None:
|
|
| 905 | + settings = [
|
|
| 906 | + Setting(SettingKind.SWITCH,
|
|
| 907 | + _('Blind Trust'),
|
|
| 908 | + SettingType.ACCOUNT_CONFIG,
|
|
| 909 | + 'omemo_blind_trust',
|
|
| 910 | + desc=_('Blindly trust new devices until you verify them'))
|
|
| 911 | + ]
|
|
| 912 | + GenericSettingPage.__init__(self, account, settings)
|
|
| 913 | + |
|
| 914 | + heading = Gtk.Label(label=_('Trust Management'))
|
|
| 915 | + heading.get_style_context().add_class('bold')
|
|
| 916 | + heading.set_xalign(0)
|
|
| 917 | + self.add(heading)
|
|
| 918 | + |
|
| 919 | + btbv_label = Gtk.Label()
|
|
| 920 | + btbv_label.set_xalign(0)
|
|
| 921 | + markup = '<a href="%s">%s</a>' % (
|
|
| 922 | + 'https://dev.gajim.org/gajim/gajim-plugins/-/'
|
|
| 923 | + 'wikis/omemogajimplugin',
|
|
| 924 | + _('Read more about blind trust'))
|
|
| 925 | + btbv_label.set_markup(markup)
|
|
| 926 | + self.add(btbv_label)
|
|
| 927 | + |
|
| 928 | + omemo_trust_manager = OMEMOTrustManager(account)
|
|
| 929 | + omemo_trust_manager.set_margin_top(18)
|
|
| 930 | + self.pack_end(omemo_trust_manager, True, True, 0)
|
|
| 931 | + self.reorder_child(omemo_trust_manager, 0)
|
|
| 932 | + |
|
| 933 | + |
|
| 894 | 934 | class ConnectionPage(GenericSettingPage):
|
| 895 | 935 | |
| 896 | 936 | name = 'connection'
|
| ... | ... | @@ -283,6 +283,8 @@ class ContactInfoBuilder(Builder): |
| 283 | 283 | to_subscription_button: Gtk.Button
|
| 284 | 284 | contact_settings_box: Gtk.Box
|
| 285 | 285 | remove_history_button: Gtk.Button
|
| 286 | + encryption_scrolled: Gtk.ScrolledWindow
|
|
| 287 | + encryption_box: Gtk.Box
|
|
| 286 | 288 | groups_page_box: Gtk.Box
|
| 287 | 289 | groups_treeview: Gtk.TreeView
|
| 288 | 290 | tree_selection: Gtk.TreeSelection
|
| ... | ... | @@ -412,6 +414,8 @@ class GroupchatDetailsBuilder(Builder): |
| 412 | 414 | main_stack: Gtk.Stack
|
| 413 | 415 | info_box: Gtk.Box
|
| 414 | 416 | settings_box: Gtk.Box
|
| 417 | + encryption_scrolled: Gtk.ScrolledWindow
|
|
| 418 | + encryption_box: Gtk.Box
|
|
| 415 | 419 | manage_box: Gtk.Box
|
| 416 | 420 | affiliation_box: Gtk.Box
|
| 417 | 421 | outcasts_box: Gtk.Box
|
| ... | ... | @@ -589,6 +593,26 @@ class MessageActionsBoxBuilder(Builder): |
| 589 | 593 | input_scrolled: Gtk.ScrolledWindow
|
| 590 | 594 | |
| 591 | 595 | |
| 596 | +class OmemoTrustManagerBuilder(Builder):
|
|
| 597 | + search_popover: Gtk.Popover
|
|
| 598 | + search: Gtk.SearchEntry
|
|
| 599 | + qr_code_popover: Gtk.Popover
|
|
| 600 | + comparing_instructions: Gtk.Label
|
|
| 601 | + our_fingerprint_2: Gtk.Label
|
|
| 602 | + qr_code_image: Gtk.Image
|
|
| 603 | + qr_dependency_missing: Gtk.Label
|
|
| 604 | + stack: Gtk.Stack
|
|
| 605 | + our_fingerprint_1: Gtk.Label
|
|
| 606 | + qr_menu_button: Gtk.MenuButton
|
|
| 607 | + manage_trust_button: Gtk.Button
|
|
| 608 | + list_heading: Gtk.Label
|
|
| 609 | + list_heading_box: Gtk.Box
|
|
| 610 | + show_inactive_switch: Gtk.Switch
|
|
| 611 | + search_button: Gtk.MenuButton
|
|
| 612 | + list: Gtk.ListBox
|
|
| 613 | + clear_devices_button: Gtk.Button
|
|
| 614 | + |
|
| 615 | + |
|
| 592 | 616 | class PasswordDialogBuilder(Builder):
|
| 593 | 617 | pass_box: Gtk.Box
|
| 594 | 618 | header: Gtk.Label
|
| ... | ... | @@ -649,6 +673,7 @@ class PreferencesBuilder(Builder): |
| 649 | 673 | stack: Gtk.Stack
|
| 650 | 674 | window_behaviour: Gtk.Grid
|
| 651 | 675 | plugins: Gtk.Grid
|
| 676 | + general: Gtk.Grid
|
|
| 652 | 677 | chats: Gtk.Grid
|
| 653 | 678 | group_chats: Gtk.Grid
|
| 654 | 679 | file_preview: Gtk.Grid
|
| ... | ... | @@ -1016,6 +1041,8 @@ def get_builder(file_name: Literal['manage_sounds.ui'], widgets: list[str] = ... |
| 1016 | 1041 | @overload
|
| 1017 | 1042 | def get_builder(file_name: Literal['message_actions_box.ui'], widgets: list[str] = ...) -> MessageActionsBoxBuilder: ...
|
| 1018 | 1043 | @overload
|
| 1044 | +def get_builder(file_name: Literal['omemo_trust_manager.ui'], widgets: list[str] = ...) -> OmemoTrustManagerBuilder: ...
|
|
| 1045 | +@overload
|
|
| 1019 | 1046 | def get_builder(file_name: Literal['password_dialog.ui'], widgets: list[str] = ...) -> PasswordDialogBuilder: ...
|
| 1020 | 1047 | @overload
|
| 1021 | 1048 | def get_builder(file_name: Literal['pep_config.ui'], widgets: list[str] = ...) -> PepConfigBuilder: ...
|
| ... | ... | @@ -718,7 +718,7 @@ def _on_send_message(self) -> None: |
| 718 | 718 | assert contact is not None
|
| 719 | 719 | |
| 720 | 720 | encryption = contact.settings.get('encryption')
|
| 721 | - if encryption:
|
|
| 721 | + if encryption and encryption != 'OMEMO':
|
|
| 722 | 722 | if encryption not in app.plugin_manager.encryption_plugins:
|
| 723 | 723 | ErrorDialog(_('Encryption error'),
|
| 724 | 724 | _('Missing necessary encryption plugin'))
|
| ... | ... | @@ -49,6 +49,7 @@ |
| 49 | 49 | from .contact_settings import ContactSettings
|
| 50 | 50 | from .dialogs import ConfirmationDialog
|
| 51 | 51 | from .dialogs import DialogButton
|
| 52 | +from .omemo_trust_manager import OMEMOTrustManager
|
|
| 52 | 53 | from .sidebar_switcher import SideBarSwitcher
|
| 53 | 54 | from .builder import get_builder
|
| 54 | 55 | from .util import connect_destroy
|
| ... | ... | @@ -109,6 +110,7 @@ def __init__(self, |
| 109 | 110 | |
| 110 | 111 | if isinstance(self.contact, BareContact):
|
| 111 | 112 | self._fill_settings_page(self.contact)
|
| 113 | + self._fill_encryption_page(self.contact)
|
|
| 112 | 114 | self._fill_device_info(self.contact)
|
| 113 | 115 | self._fill_groups_page(self.contact)
|
| 114 | 116 | self._fill_note_page(self.contact)
|
| ... | ... | @@ -120,7 +122,6 @@ def __init__(self, |
| 120 | 122 | self.connect('key-press-event', self._on_key_press)
|
| 121 | 123 | self.connect('destroy', self._on_destroy)
|
| 122 | 124 | |
| 123 | - # pylint: disable=line-too-long
|
|
| 124 | 125 | connect_destroy(self._ui.tree_selection,
|
| 125 | 126 | 'changed', self._on_group_selection_changed)
|
| 126 | 127 | connect_destroy(self._ui.toggle_renderer,
|
| ... | ... | @@ -134,7 +135,6 @@ def __init__(self, |
| 134 | 135 | ('unsubscribed-presence-received', ged.GUI1,
|
| 135 | 136 | self._on_unsubscribed_presence_received),
|
| 136 | 137 | ])
|
| 137 | - # pylint: enable=line-too-long
|
|
| 138 | 138 | |
| 139 | 139 | self.add(self._ui.main_grid)
|
| 140 | 140 | self.show_all()
|
| ... | ... | @@ -185,6 +185,11 @@ def _fill_information_page(self, contact: ContactT) -> None: |
| 185 | 185 | |
| 186 | 186 | self._switcher.set_row_visible('information', True)
|
| 187 | 187 | |
| 188 | + def _fill_encryption_page(self, contact: ContactT) -> None:
|
|
| 189 | + self._ui.encryption_box.add(
|
|
| 190 | + OMEMOTrustManager(self.contact.account, self.contact))
|
|
| 191 | + self._switcher.set_row_visible('encryption-omemo', True)
|
|
| 192 | + |
|
| 188 | 193 | def _fill_note_page(self, contact: BareContact) -> None:
|
| 189 | 194 | if not contact.is_in_roster:
|
| 190 | 195 | return
|
| ... | ... | @@ -34,6 +34,7 @@ |
| 34 | 34 | from .groupchat_config import GroupchatConfig
|
| 35 | 35 | from .groupchat_manage import GroupchatManage
|
| 36 | 36 | from .groupchat_settings import GroupChatSettings
|
| 37 | +from .omemo_trust_manager import OMEMOTrustManager
|
|
| 37 | 38 | from .sidebar_switcher import SideBarSwitcher
|
| 38 | 39 | from .structs import RemoveHistoryActionParams
|
| 39 | 40 | |
| ... | ... | @@ -71,6 +72,7 @@ def __init__(self, |
| 71 | 72 | |
| 72 | 73 | self._add_groupchat_info()
|
| 73 | 74 | self._add_groupchat_settings()
|
| 75 | + self._add_groupchat_encryption()
|
|
| 74 | 76 | self._add_groupchat_manage()
|
| 75 | 77 | self._add_affiliations()
|
| 76 | 78 | self._add_outcasts()
|
| ... | ... | @@ -173,6 +175,10 @@ def _add_groupchat_settings(self) -> None: |
| 173 | 175 | |
| 174 | 176 | self._ui.settings_box.add(scrolled_window)
|
| 175 | 177 | |
| 178 | + def _add_groupchat_encryption(self) -> None:
|
|
| 179 | + self._ui.encryption_box.add(
|
|
| 180 | + OMEMOTrustManager(self._contact.account, self._contact))
|
|
| 181 | + |
|
| 176 | 182 | def _add_affiliations(self) -> None:
|
| 177 | 183 | affiliations = GroupchatAffiliation(self._client, self._contact)
|
| 178 | 184 | self._ui.affiliation_box.add(affiliations)
|
| ... | ... | @@ -42,6 +42,7 @@ |
| 42 | 42 | from gajim.common.client import Client
|
| 43 | 43 | from gajim.common.const import SimpleClientState
|
| 44 | 44 | from gajim.common.const import Direction
|
| 45 | +from gajim.common.modules.contacts import BareContact
|
|
| 45 | 46 | from gajim.common.modules.contacts import GroupchatContact
|
| 46 | 47 | from gajim.common.modules.contacts import GroupchatParticipant
|
| 47 | 48 | from gajim.common.types import ChatContactT
|
| ... | ... | @@ -59,7 +60,7 @@ |
| 59 | 60 | from .menus import get_self_contact_menu
|
| 60 | 61 | from .menus import get_singlechat_menu
|
| 61 | 62 | from .message_input import MessageInputTextView
|
| 62 | - |
|
| 63 | +from .util import open_window
|
|
| 63 | 64 | |
| 64 | 65 | log = logging.getLogger('gajim.gui.messageactionsbox')
|
| 65 | 66 | |
| ... | ... | @@ -297,7 +298,7 @@ def _change_encryption(self, |
| 297 | 298 | if current_state == new_state:
|
| 298 | 299 | return
|
| 299 | 300 | |
| 300 | - if new_state:
|
|
| 301 | + if new_state and new_state != 'OMEMO':
|
|
| 301 | 302 | plugin = app.plugin_manager.encryption_plugins.get(new_state)
|
| 302 | 303 | if plugin is None:
|
| 303 | 304 | # TODO: Add GUI error here
|
| ... | ... | @@ -353,6 +354,9 @@ def _update_encryption_details_button(self) -> None: |
| 353 | 354 | app.window.get_control(),
|
| 354 | 355 | encryption_state)
|
| 355 | 356 | |
| 357 | + if state == 'OMEMO':
|
|
| 358 | + encryption_state['authenticated'] = True
|
|
| 359 | + |
|
| 356 | 360 | visible, enc_type, authenticated = encryption_state.values()
|
| 357 | 361 | assert isinstance(visible, bool)
|
| 358 | 362 | |
| ... | ... | @@ -378,6 +382,24 @@ def _update_encryption_details_button(self) -> None: |
| 378 | 382 | def _on_encryption_details_clicked(self, _button: Gtk.Button) -> None:
|
| 379 | 383 | contact = self.get_current_contact()
|
| 380 | 384 | encryption = contact.settings.get('encryption')
|
| 385 | + if encryption == 'OMEMO':
|
|
| 386 | + if contact.is_groupchat:
|
|
| 387 | + open_window('GroupchatDetails',
|
|
| 388 | + contact=contact,
|
|
| 389 | + page='encryption-omemo')
|
|
| 390 | + return
|
|
| 391 | + |
|
| 392 | + if isinstance(contact, BareContact) and contact.is_self:
|
|
| 393 | + window = open_window('AccountsWindow')
|
|
| 394 | + window.select_account(contact.account)
|
|
| 395 | + return
|
|
| 396 | + |
|
| 397 | + open_window('ContactInfo',
|
|
| 398 | + account=contact.account,
|
|
| 399 | + contact=contact,
|
|
| 400 | + page='encryption-omemo')
|
|
| 401 | + return
|
|
| 402 | + |
|
| 381 | 403 | app.plugin_manager.extension_point(
|
| 382 | 404 | f'encryption_dialog{encryption}', app.window.get_control())
|
| 383 | 405 |
| 1 | +# Copyright (C) 2019 Philipp Hörist <philipp AT hoerist.com>
|
|
| 2 | +#
|
|
| 3 | +# This file is part of Gajim.
|
|
| 4 | +#
|
|
| 5 | +# OMEMO Gajim Plugin is free software; you can redistribute it and/or modify
|
|
| 6 | +# it under the terms of the GNU General Public License as published
|
|
| 7 | +# by the Free Software Foundation; version 3 only.
|
|
| 8 | +#
|
|
| 9 | +# OMEMO Gajim Plugin is distributed in the hope that it will be useful,
|
|
| 10 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| 11 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| 12 | +# GNU General Public License for more details.
|
|
| 13 | +#
|
|
| 14 | +# You should have received a copy of the GNU General Public License
|
|
| 15 | +# along with OMEMO Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
|
|
| 16 | + |
|
| 17 | +from __future__ import annotations
|
|
| 18 | + |
|
| 19 | +from typing import Any
|
|
| 20 | +from typing import cast
|
|
| 21 | +from typing import Optional
|
|
| 22 | +from typing import Union
|
|
| 23 | + |
|
| 24 | +import os
|
|
| 25 | +import time
|
|
| 26 | +import locale
|
|
| 27 | +import logging
|
|
| 28 | +import tempfile
|
|
| 29 | +from packaging.version import Version as V
|
|
| 30 | + |
|
| 31 | +from pkg_resources import get_distribution
|
|
| 32 | + |
|
| 33 | +from axolotl.identitykeypair import IdentityKeyPair # pyright: ignore
|
|
| 34 | + |
|
| 35 | +from nbxmpp.protocol import JID
|
|
| 36 | + |
|
| 37 | +from gi.repository import Gtk
|
|
| 38 | +from gi.repository import GdkPixbuf
|
|
| 39 | + |
|
| 40 | +from gajim.common import app
|
|
| 41 | +from gajim.common import ged
|
|
| 42 | +from gajim.common import types
|
|
| 43 | +from gajim.common.events import AccountConnected
|
|
| 44 | +from gajim.common.events import AccountDisconnected
|
|
| 45 | +from gajim.common.i18n import _
|
|
| 46 | +from gajim.common.ged import EventHelper
|
|
| 47 | +from gajim.common.modules.contacts import BareContact
|
|
| 48 | +from gajim.common.modules.omemobackend.util import Trust
|
|
| 49 | +from gajim.common.modules.omemobackend.util import IdentityKeyExtended
|
|
| 50 | +from gajim.common.modules.omemobackend.util import get_fingerprint
|
|
| 51 | + |
|
| 52 | +from .builder import get_builder
|
|
| 53 | +from .dialogs import ConfirmationDialog
|
|
| 54 | +from .dialogs import DialogButton
|
|
| 55 | +from .util import open_window
|
|
| 56 | + |
|
| 57 | +log = logging.getLogger('gajim.gui.omemo_trust_dialog')
|
|
| 58 | + |
|
| 59 | + |
|
| 60 | +TRUST_DATA = {
|
|
| 61 | + Trust.UNTRUSTED: ('dialog-error-symbolic',
|
|
| 62 | + _('Untrusted'),
|
|
| 63 | + 'error-color'),
|
|
| 64 | + Trust.UNDECIDED: ('security-low-symbolic',
|
|
| 65 | + _('Not Decided'),
|
|
| 66 | + 'warning-color'),
|
|
| 67 | + Trust.VERIFIED: ('security-high-symbolic',
|
|
| 68 | + _('Verified'),
|
|
| 69 | + 'encrypted-color'),
|
|
| 70 | + Trust.BLIND: ('security-medium-symbolic',
|
|
| 71 | + _('Blind Trust'),
|
|
| 72 | + 'encrypted-color')
|
|
| 73 | +}
|
|
| 74 | + |
|
| 75 | + |
|
| 76 | +class OMEMOTrustManager(Gtk.Box, EventHelper):
|
|
| 77 | + def __init__(self,
|
|
| 78 | + account: str,
|
|
| 79 | + contact: Optional[types.ChatContactT] = None
|
|
| 80 | + ) -> None:
|
|
| 81 | + |
|
| 82 | + Gtk.Box.__init__(self)
|
|
| 83 | + EventHelper.__init__(self)
|
|
| 84 | + |
|
| 85 | + self._account = account
|
|
| 86 | + self._contact = contact
|
|
| 87 | + |
|
| 88 | + self._ui = get_builder('omemo_trust_manager.ui')
|
|
| 89 | + self.add(self._ui.stack)
|
|
| 90 | + |
|
| 91 | + self._ui.list.set_filter_func(self._filter_func, None)
|
|
| 92 | + self._ui.list.set_sort_func(self._sort_func, None)
|
|
| 93 | + |
|
| 94 | + self._ui.connect_signals(self)
|
|
| 95 | + |
|
| 96 | + self.connect('destroy', self._on_destroy)
|
|
| 97 | + self.show_all()
|
|
| 98 | + |
|
| 99 | + self.register_events([
|
|
| 100 | + ('account-connected', ged.GUI2, self._on_account_state),
|
|
| 101 | + ('account-disconnected', ged.GUI2, self._on_account_state)
|
|
| 102 | + ])
|
|
| 103 | + |
|
| 104 | + if not app.account_is_connected(account):
|
|
| 105 | + self._ui.stack.set_visible_child_name('no-connection')
|
|
| 106 | + return
|
|
| 107 | + |
|
| 108 | + self._update()
|
|
| 109 | + |
|
| 110 | + def _update(self) -> None:
|
|
| 111 | + client = app.get_client(self._account)
|
|
| 112 | + if self._contact is None:
|
|
| 113 | + self._contact = client.get_module('Contacts').get_contact(
|
|
| 114 | + client.get_own_jid().bare)
|
|
| 115 | + |
|
| 116 | + if isinstance(self._contact, BareContact) and self._contact.is_self:
|
|
| 117 | + header_text = _('Other devices connected with your account')
|
|
| 118 | + popover_qr_text = _('Compare this code with the one shown on your '
|
|
| 119 | + 'contact’s screen to ensure the safety of '
|
|
| 120 | + 'your end-to-end encrypted chat.')
|
|
| 121 | + else:
|
|
| 122 | + header_text = _('Devices connected with %s') % self._contact.name
|
|
| 123 | + popover_qr_text = _('Compare this code with the one shown on your '
|
|
| 124 | + 'contact’s screen to ensure the safety of '
|
|
| 125 | + 'your end-to-end encrypted chat '
|
|
| 126 | + 'with %s.') % self._contact.name
|
|
| 127 | + |
|
| 128 | + self._ui.list_heading.set_text(header_text)
|
|
| 129 | + self._ui.comparing_instructions.set_text(popover_qr_text)
|
|
| 130 | + |
|
| 131 | + self._omemo = client.get_module('OMEMO')
|
|
| 132 | + |
|
| 133 | + self._identity_key = cast(
|
|
| 134 | + IdentityKeyPair, self._omemo.backend.storage.getIdentityKeyPair())
|
|
| 135 | + our_fpr_formatted = get_fingerprint(self._identity_key, formatted=True)
|
|
| 136 | + self._ui.our_fingerprint_1.set_text(our_fpr_formatted)
|
|
| 137 | + self._ui.our_fingerprint_2.set_text(our_fpr_formatted)
|
|
| 138 | + |
|
| 139 | + self.update()
|
|
| 140 | + self._load_qrcode()
|
|
| 141 | + |
|
| 142 | + def update(self) -> None:
|
|
| 143 | + assert self._contact is not None
|
|
| 144 | + self._ui.list.foreach(self._ui.list.remove)
|
|
| 145 | + |
|
| 146 | + if isinstance(self._contact, BareContact) and self._contact.is_self:
|
|
| 147 | + self._ui.clear_devices_button.show()
|
|
| 148 | + self._ui.list_heading_box.set_halign(Gtk.Align.START)
|
|
| 149 | + else:
|
|
| 150 | + self._ui.manage_trust_button.show()
|
|
| 151 | + if self._contact.is_groupchat:
|
|
| 152 | + self._ui.search_button.show()
|
|
| 153 | + |
|
| 154 | + self._load_fingerprints(self._contact)
|
|
| 155 | + |
|
| 156 | + def _on_destroy(self, *args: Any) -> None:
|
|
| 157 | + app.check_finalize(self)
|
|
| 158 | + |
|
| 159 | + def _on_account_state(self,
|
|
| 160 | + event: Union[AccountConnected, AccountDisconnected]
|
|
| 161 | + ) -> None:
|
|
| 162 | + |
|
| 163 | + if isinstance(event, AccountConnected):
|
|
| 164 | + self._update()
|
|
| 165 | + self._ui.stack.set_visible_child_name('manage-keys')
|
|
| 166 | + else:
|
|
| 167 | + self._ui.stack.set_visible_child_name('no-connection')
|
|
| 168 | + |
|
| 169 | + def _filter_func(self, row: KeyRow, _user_data: Any) -> bool:
|
|
| 170 | + search_text = self._ui.search.get_text()
|
|
| 171 | + if search_text and search_text.lower() not in str(row.jid):
|
|
| 172 | + return False
|
|
| 173 | + if self._ui.show_inactive_switch.get_active():
|
|
| 174 | + return True
|
|
| 175 | + return row.active
|
|
| 176 | + |
|
| 177 | + @staticmethod
|
|
| 178 | + def _sort_func(row1: KeyRow, row2: KeyRow, _user_data: Any) -> int:
|
|
| 179 | + result = locale.strcoll(str(row1.jid), str(row2.jid))
|
|
| 180 | + if result != 0:
|
|
| 181 | + return result
|
|
| 182 | + |
|
| 183 | + if row1.active != row2.active:
|
|
| 184 | + return -1 if row1.active else 1
|
|
| 185 | + |
|
| 186 | + if row1.trust != row2.trust:
|
|
| 187 | + return -1 if row1.trust > row2.trust else 1
|
|
| 188 | + return 0
|
|
| 189 | + |
|
| 190 | + def _on_search_changed(self, _entry: Gtk.SearchEntry) -> None:
|
|
| 191 | + self._ui.list.invalidate_filter()
|
|
| 192 | + |
|
| 193 | + def _load_fingerprints(self, contact: types.ChatContactT) -> None:
|
|
| 194 | + if contact.is_groupchat:
|
|
| 195 | + members = list(self._omemo.backend.get_muc_members(
|
|
| 196 | + str(contact.jid)))
|
|
| 197 | + sessions = self._omemo.backend.storage.getSessionsFromJids(members)
|
|
| 198 | + results = self._omemo.backend.storage.getMucFingerprints(members)
|
|
| 199 | + else:
|
|
| 200 | + sessions = self._omemo.backend.storage.getSessionsFromJid(
|
|
| 201 | + str(contact.jid))
|
|
| 202 | + results = self._omemo.backend.storage.getFingerprints(
|
|
| 203 | + str(contact.jid))
|
|
| 204 | + |
|
| 205 | + rows: dict[IdentityKeyExtended, KeyRow] = {}
|
|
| 206 | + for result in results:
|
|
| 207 | + rows[result.public_key] = KeyRow(contact,
|
|
| 208 | + result.recipient_id,
|
|
| 209 | + result.public_key,
|
|
| 210 | + result.trust,
|
|
| 211 | + result.timestamp)
|
|
| 212 | + |
|
| 213 | + for item in sessions:
|
|
| 214 | + if item.record.isFresh():
|
|
| 215 | + return
|
|
| 216 | + identity_key = item.record.getSessionState().getRemoteIdentityKey()
|
|
| 217 | + identity_key = IdentityKeyExtended(identity_key.getPublicKey())
|
|
| 218 | + try:
|
|
| 219 | + key_row = rows[identity_key]
|
|
| 220 | + except KeyError:
|
|
| 221 | + log.warning('Could not find session identitykey %s',
|
|
| 222 | + item.device_id)
|
|
| 223 | + self._omemo.backend.storage.deleteSession(item.recipient_id,
|
|
| 224 | + item.device_id)
|
|
| 225 | + continue
|
|
| 226 | + |
|
| 227 | + key_row.active = item.active
|
|
| 228 | + key_row.device_id = item.device_id
|
|
| 229 | + |
|
| 230 | + for row in rows.values():
|
|
| 231 | + self._ui.list.add(row)
|
|
| 232 | + |
|
| 233 | + @staticmethod
|
|
| 234 | + def _get_qrcode(jid: str, sid: int, identity_key: IdentityKeyPair) -> str:
|
|
| 235 | + fingerprint = get_fingerprint(identity_key)
|
|
| 236 | + path = os.path.join(tempfile.gettempdir(),
|
|
| 237 | + 'omemo_{}.png'.format(jid))
|
|
| 238 | + |
|
| 239 | + ver_string = 'xmpp:{}?omemo-sid-{}={}'.format(jid, sid, fingerprint)
|
|
| 240 | + log.debug('Verification String: %s', ver_string)
|
|
| 241 | + |
|
| 242 | + import qrcode
|
|
| 243 | + qr = qrcode.QRCode(version=None,
|
|
| 244 | + error_correction=qrcode.constants.ERROR_CORRECT_L,
|
|
| 245 | + box_size=6,
|
|
| 246 | + border=4)
|
|
| 247 | + qr.add_data(ver_string)
|
|
| 248 | + qr.make(fit=True)
|
|
| 249 | + |
|
| 250 | + fill_color = 'black'
|
|
| 251 | + back_color = 'white'
|
|
| 252 | + if V(get_distribution('qrcode').version) < V('6.0'):
|
|
| 253 | + # meaning of fill_color and back_color were switched
|
|
| 254 | + # before this commit in qrcode between versions 5.3
|
|
| 255 | + # and 6.0: https://github.com/lincolnloop/python-qrcode/
|
|
| 256 | + # commit/01f440d64b7d1f61bb75161ce118b86eca85b15c
|
|
| 257 | + back_color, fill_color = fill_color, back_color
|
|
| 258 | + |
|
| 259 | + img = qr.make_image(fill_color=fill_color, back_color=back_color)
|
|
| 260 | + img.save(path)
|
|
| 261 | + return path
|
|
| 262 | + |
|
| 263 | + def _load_qrcode(self) -> None:
|
|
| 264 | + try:
|
|
| 265 | + client = app.get_client(self._account)
|
|
| 266 | + path = self._get_qrcode(client.get_own_jid().bare,
|
|
| 267 | + self._omemo.backend.own_device,
|
|
| 268 | + self._identity_key)
|
|
| 269 | + except ImportError:
|
|
| 270 | + log.exception('Failed to generate QR code')
|
|
| 271 | + self._ui.qr_code_image.hide()
|
|
| 272 | + self._ui.qr_dependency_missing.show()
|
|
| 273 | + else:
|
|
| 274 | + pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
|
|
| 275 | + self._ui.qr_code_image.set_from_pixbuf(pixbuf)
|
|
| 276 | + self._ui.qr_code_image.show()
|
|
| 277 | + self._ui.qr_dependency_missing.hide()
|
|
| 278 | + |
|
| 279 | + def _on_show_inactive(self, switch: Gtk.Switch, _param: Any) -> None:
|
|
| 280 | + self._ui.list.invalidate_filter()
|
|
| 281 | + |
|
| 282 | + def _on_clear_devices_clicked(self, _button: Gtk.Button) -> None:
|
|
| 283 | + def _clear():
|
|
| 284 | + self._omemo.clear_devicelist()
|
|
| 285 | + |
|
| 286 | + window = self.get_window()
|
|
| 287 | + assert isinstance(window, Gtk.Window)
|
|
| 288 | + |
|
| 289 | + ConfirmationDialog(
|
|
| 290 | + _('Clear Devices'),
|
|
| 291 | + _('Clear Devices Now?'),
|
|
| 292 | + _('This will clear the devices store for your account.'),
|
|
| 293 | + [DialogButton.make('Cancel'),
|
|
| 294 | + DialogButton.make('Accept',
|
|
| 295 | + text=_('_Clear Devices'),
|
|
| 296 | + callback=_clear)],
|
|
| 297 | + transient_for=window).show()
|
|
| 298 | + |
|
| 299 | + def _on_manage_trust_clicked(self, _button: Gtk.Button) -> None:
|
|
| 300 | + assert self._contact is not None
|
|
| 301 | + window = open_window('AccountsWindow')
|
|
| 302 | + window.select_account(self._contact.account)
|
|
| 303 | + |
|
| 304 | + |
|
| 305 | +class KeyRow(Gtk.ListBoxRow):
|
|
| 306 | + def __init__(self,
|
|
| 307 | + contact: types.ChatContactT,
|
|
| 308 | + jid: JID,
|
|
| 309 | + identity_key: IdentityKeyExtended,
|
|
| 310 | + trust: Trust,
|
|
| 311 | + last_seen: Optional[float]
|
|
| 312 | + ) -> None:
|
|
| 313 | + |
|
| 314 | + Gtk.ListBoxRow.__init__(self)
|
|
| 315 | + self.set_activatable(False)
|
|
| 316 | + |
|
| 317 | + self._active = False
|
|
| 318 | + self._device_id: Optional[int] = None
|
|
| 319 | + self._identity_key = identity_key
|
|
| 320 | + self.trust = trust
|
|
| 321 | + self.jid = jid
|
|
| 322 | + |
|
| 323 | + client = app.get_client(contact.account)
|
|
| 324 | + self._omemo = client.get_module('OMEMO')
|
|
| 325 | + |
|
| 326 | + grid = Gtk.Grid()
|
|
| 327 | + grid.set_column_spacing(12)
|
|
| 328 | + |
|
| 329 | + self._trust_button = TrustButton(self)
|
|
| 330 | + grid.attach(self._trust_button, 1, 1, 1, 3)
|
|
| 331 | + |
|
| 332 | + self.fingerprint = Gtk.Label(
|
|
| 333 | + label=self._identity_key.get_fingerprint(formatted=True))
|
|
| 334 | + self.fingerprint.get_style_context().add_class('omemo-mono')
|
|
| 335 | + self.fingerprint.get_style_context().add_class('omemo-inactive-color')
|
|
| 336 | + self.fingerprint.set_selectable(True)
|
|
| 337 | + self.fingerprint.set_halign(Gtk.Align.START)
|
|
| 338 | + self.fingerprint.set_valign(Gtk.Align.START)
|
|
| 339 | + self.fingerprint.set_hexpand(True)
|
|
| 340 | + grid.attach(self.fingerprint, 2, 1, 1, 1)
|
|
| 341 | + |
|
| 342 | + if last_seen is not None:
|
|
| 343 | + last_seen_str = time.strftime('%d-%m-%Y %H:%M:%S',
|
|
| 344 | + time.localtime(last_seen))
|
|
| 345 | + else:
|
|
| 346 | + last_seen_str = _('Never')
|
|
| 347 | + last_seen_label = Gtk.Label(label=_('Last seen: %s') % last_seen_str)
|
|
| 348 | + last_seen_label.set_halign(Gtk.Align.START)
|
|
| 349 | + last_seen_label.set_valign(Gtk.Align.START)
|
|
| 350 | + last_seen_label.set_hexpand(True)
|
|
| 351 | + last_seen_label.get_style_context().add_class('small-label')
|
|
| 352 | + last_seen_label.get_style_context().add_class('dim-label')
|
|
| 353 | + grid.attach(last_seen_label, 2, 3, 1, 1)
|
|
| 354 | + |
|
| 355 | + self.add(grid)
|
|
| 356 | + self.show_all()
|
|
| 357 | + |
|
| 358 | + def delete_fingerprint(self, *args: Any) -> None:
|
|
| 359 | + listbox = cast(Gtk.ListBox, self.get_parent())
|
|
| 360 | + window = cast(Gtk.Window, listbox.get_window())
|
|
| 361 | + |
|
| 362 | + def _remove():
|
|
| 363 | + self._omemo.backend.remove_device(str(self.jid), self.device_id)
|
|
| 364 | + self._omemo.backend.storage.deleteSession(
|
|
| 365 | + str(self.jid), self.device_id)
|
|
| 366 | + self._omemo.backend.storage.deleteIdentity(
|
|
| 367 | + str(self.jid), self._identity_key)
|
|
| 368 | + |
|
| 369 | + listbox.remove(self)
|
|
| 370 | + self.destroy()
|
|
| 371 | + |
|
| 372 | + ConfirmationDialog(
|
|
| 373 | + _('Delete'),
|
|
| 374 | + _('Delete Fingerprint'),
|
|
| 375 | + _('Doing so will permanently delete this Fingerprint'),
|
|
| 376 | + [DialogButton.make('Cancel'),
|
|
| 377 | + DialogButton.make('Remove',
|
|
| 378 | + text=_('Delete'),
|
|
| 379 | + callback=_remove)],
|
|
| 380 | + transient_for=window).show()
|
|
| 381 | + |
|
| 382 | + def set_trust(self) -> None:
|
|
| 383 | + icon_name, tooltip, css_class = TRUST_DATA[self.trust]
|
|
| 384 | + image = cast(Gtk.Image, self._trust_button.get_child())
|
|
| 385 | + image.set_from_icon_name(icon_name, Gtk.IconSize.MENU)
|
|
| 386 | + image.get_style_context().add_class(css_class)
|
|
| 387 | + image.set_tooltip_text(tooltip)
|
|
| 388 | + |
|
| 389 | + self._omemo.backend.storage.setTrust(
|
|
| 390 | + str(self.jid), self._identity_key, self.trust)
|
|
| 391 | + |
|
| 392 | + @property
|
|
| 393 | + def active(self) -> bool:
|
|
| 394 | + return self._active
|
|
| 395 | + |
|
| 396 | + @active.setter
|
|
| 397 | + def active(self, active: bool) -> None:
|
|
| 398 | + context = self.fingerprint.get_style_context()
|
|
| 399 | + self._active = bool(active)
|
|
| 400 | + if self._active:
|
|
| 401 | + context.remove_class('omemo-inactive-color')
|
|
| 402 | + else:
|
|
| 403 | + context.add_class('omemo-inactive-color')
|
|
| 404 | + self._trust_button.update()
|
|
| 405 | + |
|
| 406 | + @property
|
|
| 407 | + def device_id(self) -> Optional[int]:
|
|
| 408 | + return self._device_id
|
|
| 409 | + |
|
| 410 | + @device_id.setter
|
|
| 411 | + def device_id(self, device_id: int) -> None:
|
|
| 412 | + self._device_id = device_id
|
|
| 413 | + |
|
| 414 | + |
|
| 415 | +class TrustButton(Gtk.MenuButton):
|
|
| 416 | + def __init__(self, row: KeyRow) -> None:
|
|
| 417 | + Gtk.MenuButton.__init__(self)
|
|
| 418 | + self._row = row
|
|
| 419 | + self._css_class = ''
|
|
| 420 | + self.set_popover(TrustPopver(row))
|
|
| 421 | + self.set_valign(Gtk.Align.CENTER)
|
|
| 422 | + self.update()
|
|
| 423 | + |
|
| 424 | + def update(self) -> None:
|
|
| 425 | + icon_name, tooltip, css_class = TRUST_DATA[self._row.trust]
|
|
| 426 | + image = cast(Gtk.Image, self.get_child())
|
|
| 427 | + image.set_from_icon_name(icon_name, Gtk.IconSize.MENU)
|
|
| 428 | + image.get_style_context().remove_class(self._css_class)
|
|
| 429 | + |
|
| 430 | + if not self._row.active:
|
|
| 431 | + css_class = 'omemo-inactive-color'
|
|
| 432 | + tooltip = '%s - %s' % (_('Inactive'), tooltip)
|
|
| 433 | + |
|
| 434 | + image.get_style_context().add_class(css_class)
|
|
| 435 | + self._css_class = css_class
|
|
| 436 | + self.set_tooltip_text(tooltip)
|
|
| 437 | + |
|
| 438 | + |
|
| 439 | +class TrustPopver(Gtk.Popover):
|
|
| 440 | + def __init__(self, row: KeyRow) -> None:
|
|
| 441 | + Gtk.Popover.__init__(self)
|
|
| 442 | + self._row = row
|
|
| 443 | + self._listbox = Gtk.ListBox()
|
|
| 444 | + self._listbox.set_selection_mode(Gtk.SelectionMode.NONE)
|
|
| 445 | + self.update()
|
|
| 446 | + self.add(self._listbox)
|
|
| 447 | + self._listbox.show_all()
|
|
| 448 | + self._listbox.connect('row-activated', self._activated)
|
|
| 449 | + self.get_style_context().add_class('omemo-trust-popover')
|
|
| 450 | + |
|
| 451 | + def _activated(self, _listbox: Gtk.ListBox, row: MenuOption) -> None:
|
|
| 452 | + self.popdown()
|
|
| 453 | + if row.type_ is None:
|
|
| 454 | + self._row.delete_fingerprint()
|
|
| 455 | + else:
|
|
| 456 | + self._row.trust = row.type_
|
|
| 457 | + self._row.set_trust()
|
|
| 458 | + trust_button = cast(TrustButton, self.get_relative_to())
|
|
| 459 | + trust_button.update()
|
|
| 460 | + self.update()
|
|
| 461 | + |
|
| 462 | + def update(self) -> None:
|
|
| 463 | + self._listbox.foreach(self._listbox.remove)
|
|
| 464 | + if self._row.trust != Trust.VERIFIED:
|
|
| 465 | + self._listbox.add(VerifiedOption())
|
|
| 466 | + if self._row.trust != Trust.BLIND:
|
|
| 467 | + self._listbox.add(BlindOption())
|
|
| 468 | + if self._row.trust != Trust.UNTRUSTED:
|
|
| 469 | + self._listbox.add(NotTrustedOption())
|
|
| 470 | + self._listbox.add(DeleteOption())
|
|
| 471 | + |
|
| 472 | + |
|
| 473 | +class MenuOption(Gtk.ListBoxRow):
|
|
| 474 | + def __init__(self,
|
|
| 475 | + icon: str,
|
|
| 476 | + label_text: str,
|
|
| 477 | + color: str,
|
|
| 478 | + type_: Optional[Trust] = None
|
|
| 479 | + ) -> None:
|
|
| 480 | + |
|
| 481 | + Gtk.ListBoxRow.__init__(self)
|
|
| 482 | + |
|
| 483 | + self.type_ = type_
|
|
| 484 | + self.icon = icon
|
|
| 485 | + self.label = label_text
|
|
| 486 | + self.color = color
|
|
| 487 | + |
|
| 488 | + box = Gtk.Box()
|
|
| 489 | + box.set_spacing(6)
|
|
| 490 | + |
|
| 491 | + image = Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.MENU)
|
|
| 492 | + label = Gtk.Label(label=label_text)
|
|
| 493 | + image.get_style_context().add_class(color)
|
|
| 494 | + |
|
| 495 | + box.add(image)
|
|
| 496 | + box.add(label)
|
|
| 497 | + self.add(box)
|
|
| 498 | + self.show_all()
|
|
| 499 | + |
|
| 500 | + |
|
| 501 | +class BlindOption(MenuOption):
|
|
| 502 | + def __init__(self) -> None:
|
|
| 503 | + MenuOption.__init__(self,
|
|
| 504 | + 'security-medium-symbolic',
|
|
| 505 | + _('Blind Trust'),
|
|
| 506 | + 'encrypted-color',
|
|
| 507 | + Trust.BLIND)
|
|
| 508 | + |
|
| 509 | + |
|
| 510 | +class VerifiedOption(MenuOption):
|
|
| 511 | + def __init__(self) -> None:
|
|
| 512 | + MenuOption.__init__(self,
|
|
| 513 | + 'security-high-symbolic',
|
|
| 514 | + _('Verified'),
|
|
| 515 | + 'encrypted-color',
|
|
| 516 | + Trust.VERIFIED)
|
|
| 517 | + |
|
| 518 | + |
|
| 519 | +class NotTrustedOption(MenuOption):
|
|
| 520 | + def __init__(self) -> None:
|
|
| 521 | + MenuOption.__init__(self,
|
|
| 522 | + 'dialog-error-symbolic',
|
|
| 523 | + _('Untrusted'),
|
|
| 524 | + 'error-color',
|
|
| 525 | + Trust.UNTRUSTED)
|
|
| 526 | + |
|
| 527 | + |
|
| 528 | +class DeleteOption(MenuOption):
|
|
| 529 | + def __init__(self) -> None:
|
|
| 530 | + MenuOption.__init__(self,
|
|
| 531 | + 'user-trash-symbolic',
|
|
| 532 | + _('Delete'),
|
|
| 533 | + '') |