[omemo] Port UI changes from master
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,298 +1,299 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="2.16"/>
|
||||
<!-- interface-naming-policy toplevel-contextual -->
|
||||
<object class="GtkListStore" id="account_store">
|
||||
<columns>
|
||||
<!-- column-name accountname -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkListStore" id="fingerprint_store">
|
||||
<columns>
|
||||
<!-- column-name id -->
|
||||
<column type="gint"/>
|
||||
<!-- column-name screenname -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name trust -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name fingerprint -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkNotebook" id="notebook1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<signal name="switch-page" handler="update_context_list" after="yes" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow1">
|
||||
<property name="height_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">automatic</property>
|
||||
<property name="vscrollbar_policy">automatic</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="fingerprint_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="model">fingerprint_store</property>
|
||||
<property name="search_column">0</property>
|
||||
<property name="tooltip_column">3</property>
|
||||
<signal name="button-press-event" handler="fpr_button_pressed_cb" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="name_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Name</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext2"/>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="trust_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Trust</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertoggle1"/>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="fingerprint_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Fingerprint</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext4"/>
|
||||
<attributes>
|
||||
<attribute name="markup">3</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="trust_button">
|
||||
<property name="label" translatable="yes" comments="button">Trust/Revoke Fingerprint</property>
|
||||
<property name="width_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="trust_button_clicked_cb" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes" comments="tab label">Contact</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="fingerprint_label_desc1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes" comments="Descriptive label">Own Fingerprint:</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="fingerprint_label_own">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label"><tt>-------- -------- -------- -------- -------- </tt></property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="selectable">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow2">
|
||||
<property name="height_request">100</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">automatic</property>
|
||||
<property name="vscrollbar_policy">automatic</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="fingerprint_view_own">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="model">fingerprint_store</property>
|
||||
<property name="headers_clickable">False</property>
|
||||
<property name="search_column">0</property>
|
||||
<property name="tooltip_column">3</property>
|
||||
<signal name="button-press-event" handler="fpr_button_pressed_cb" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="name_column1">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Name</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext1"/>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="trust_column1">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Trust</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertoggle2"/>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="fingerprint_column1">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Fingerprint</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext3"/>
|
||||
<attributes>
|
||||
<attribute name="markup">3</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="trust_button1">
|
||||
<property name="label" translatable="yes" comments="button">Trust/Revoke Fingerprint</property>
|
||||
<property name="width_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="trust_button_clicked_cb" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Own Devices</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkMenu" id="fprclipboard_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="copyfprclipboard_item">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes" comments="Context menu item">Copy to clipboard</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="clipboard_button_cb" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.18.3 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.0"/>
|
||||
<object class="GtkListStore" id="fingerprint_store">
|
||||
<columns>
|
||||
<!-- column-name id -->
|
||||
<column type="gint"/>
|
||||
<!-- column-name screenname -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name trust -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name fingerprint -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name deviceid -->
|
||||
<column type="gint"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkNotebook" id="notebook1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<signal name="switch-page" handler="update_context_list" after="yes" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow1">
|
||||
<property name="height_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="fingerprint_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="model">fingerprint_store</property>
|
||||
<property name="headers_clickable">False</property>
|
||||
<property name="search_column">0</property>
|
||||
<property name="tooltip_column">3</property>
|
||||
<signal name="button-press-event" handler="fpr_button_pressed_cb" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection" id="treeview-selection1"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="name_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Name</property>
|
||||
<property name="clickable">True</property>
|
||||
<property name="sort_indicator">True</property>
|
||||
<property name="sort_column_id">1</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="NameCell"/>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="trust_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Trust</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="TrustCell"/>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="fingerprint_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Fingerprint</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="FingerprintCell"/>
|
||||
<attributes>
|
||||
<attribute name="markup">3</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="trust_button">
|
||||
<property name="label" translatable="yes" comments="button">Trust/Revoke Fingerprint</property>
|
||||
<property name="width_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="trust_button_clicked_cb" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes" comments="tab label">Contact</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="fingerprint_label_desc1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes" comments="Descriptive label">Own Fingerprint:</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="fingerprint_label_own">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label"><tt>-------- -------- -------- -------- -------- </tt></property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="selectable">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow2">
|
||||
<property name="height_request">100</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="fingerprint_view_own">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="model">fingerprint_store</property>
|
||||
<property name="headers_clickable">False</property>
|
||||
<property name="search_column">0</property>
|
||||
<property name="tooltip_column">3</property>
|
||||
<signal name="button-press-event" handler="fpr_button_pressed_cb" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection" id="treeview-selection2"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="name_column1">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Name</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="NameCell1"/>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="trust_column1">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Trust</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="TrustCell2"/>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="fingerprint_column1">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Fingerprint</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="FingerprintCell1"/>
|
||||
<attributes>
|
||||
<attribute name="markup">3</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="trust_button1">
|
||||
<property name="label" translatable="yes" comments="button">Trust/Revoke Fingerprint</property>
|
||||
<property name="width_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="trust_button_clicked_cb" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Own Devices</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkMenu" id="fprclipboard_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="copyfprclipboard_item">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<signal name="activate" handler="clipboard_button_cb" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
601
omemo/ui.py
601
omemo/ui.py
@@ -20,18 +20,30 @@
|
||||
|
||||
import binascii
|
||||
import logging
|
||||
import os
|
||||
import message_control
|
||||
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GObject, Gtk, GdkPixbuf
|
||||
|
||||
# pylint: disable=import-error
|
||||
import gtkgui_helpers
|
||||
from common import gajim
|
||||
from dialogs import YesNoDialog
|
||||
from plugins.gui import GajimPluginConfigDialog
|
||||
# pylint: enable=import-error
|
||||
from axolotl.state.sessionrecord import SessionRecord
|
||||
from common import configpaths
|
||||
|
||||
log = logging.getLogger('gajim.plugin_system.omemo')
|
||||
|
||||
PILLOW = False
|
||||
try:
|
||||
import qrcode
|
||||
PILLOW = True
|
||||
except Exception as e:
|
||||
log.exception('Error:')
|
||||
log.error('python-qrcode or dependencies of it, are not available')
|
||||
|
||||
# pylint: enable=import-error
|
||||
UNDECIDED = 2
|
||||
TRUSTED = 1
|
||||
UNTRUSTED = 0
|
||||
@@ -106,6 +118,12 @@ class Ui(object):
|
||||
self.account = self.contact.account.name
|
||||
self.windowinstances = {}
|
||||
|
||||
self.groupchat = False
|
||||
if chat_control.type_id == message_control.TYPE_GC:
|
||||
self.groupchat = True
|
||||
self.omemo_capable = False
|
||||
self.room = self.chat_control.room_jid
|
||||
|
||||
self.display_omemo_state()
|
||||
self.refresh_auth_lock_icon()
|
||||
|
||||
@@ -133,6 +151,9 @@ class Ui(object):
|
||||
item.set_image(Gtk.Image.new_from_file(icon_path))
|
||||
item.set_submenu(submenu)
|
||||
|
||||
if self.groupchat:
|
||||
item.set_sensitive(self.omemo_capable)
|
||||
|
||||
# at index 8 is the separator after the esession encryption entry
|
||||
menu.insert(item, 8)
|
||||
return menu
|
||||
@@ -159,7 +180,38 @@ class Ui(object):
|
||||
log.debug(self.account + ' => Sending Message to ' +
|
||||
self.contact.jid)
|
||||
|
||||
self.chat_control.send_message = omemo_send_message
|
||||
def omemo_send_gc_message(message, xhtml=None, process_commands=True):
|
||||
self.new_fingerprints_available()
|
||||
if self.encryption_active():
|
||||
missing = True
|
||||
own_jid = gajim.get_jid_from_account(self.account)
|
||||
for nick in self.plugin.groupchat[self.room]:
|
||||
real_jid = self.plugin.groupchat[self.room][nick]
|
||||
if real_jid == own_jid:
|
||||
continue
|
||||
if not self.plugin.are_keys_missing(self.account,
|
||||
real_jid):
|
||||
missing = False
|
||||
if missing:
|
||||
log.debug(self.account +
|
||||
' => No Trusted Fingerprints for ' +
|
||||
self.room)
|
||||
self.no_trusted_fingerprints_warning()
|
||||
else:
|
||||
self.chat_control.orig_send_message(message, xhtml,
|
||||
process_commands)
|
||||
log.debug(self.account + ' => Sending Message to ' +
|
||||
self.room)
|
||||
else:
|
||||
self.chat_control.orig_send_message(message, xhtml,
|
||||
process_commands)
|
||||
log.debug(self.account + ' => Sending Message to ' +
|
||||
self.room)
|
||||
|
||||
if self.groupchat:
|
||||
self.chat_control.send_message = omemo_send_gc_message
|
||||
else:
|
||||
self.chat_control.send_message = omemo_send_message
|
||||
|
||||
def set_omemo_state(self, enabled):
|
||||
"""
|
||||
@@ -182,6 +234,12 @@ class Ui(object):
|
||||
self.omemobutton.set_omemo_state(enabled)
|
||||
self.display_omemo_state()
|
||||
|
||||
def sensitive(self, value):
|
||||
self.omemobutton.set_sensitive(value)
|
||||
self.omemo_capable = value
|
||||
if value:
|
||||
self.chat_control.prepare_context_menu
|
||||
|
||||
def encryption_active(self):
|
||||
return self.state.encryption.is_active(self.contact.jid)
|
||||
|
||||
@@ -190,16 +248,31 @@ class Ui(object):
|
||||
self.set_omemo_state(True)
|
||||
|
||||
def new_fingerprints_available(self):
|
||||
fingerprints = self.state.store.getNewFingerprints(self.contact.jid)
|
||||
if fingerprints:
|
||||
self.show_fingerprint_window(fingerprints)
|
||||
jid = self.contact.jid
|
||||
if self.groupchat and self.room in self.plugin.groupchat:
|
||||
for nick in self.plugin.groupchat[self.room]:
|
||||
real_jid = self.plugin.groupchat[self.room][nick]
|
||||
fingerprints = self.state.store. \
|
||||
getNewFingerprints(real_jid)
|
||||
if fingerprints:
|
||||
self.show_fingerprint_window(fingerprints)
|
||||
elif not self.groupchat:
|
||||
fingerprints = self.state.store.getNewFingerprints(jid)
|
||||
if fingerprints:
|
||||
self.show_fingerprint_window(fingerprints)
|
||||
|
||||
def show_fingerprint_window(self, fingerprints=None):
|
||||
if 'dialog' not in self.windowinstances:
|
||||
self.windowinstances['dialog'] = \
|
||||
FingerprintWindow(self.plugin, self.contact,
|
||||
self.chat_control.parent_win.window,
|
||||
self.windowinstances)
|
||||
if self.groupchat:
|
||||
self.windowinstances['dialog'] = \
|
||||
FingerprintWindow(self.plugin, self.contact,
|
||||
self.chat_control.parent_win.window,
|
||||
self.windowinstances, groupchat=True)
|
||||
else:
|
||||
self.windowinstances['dialog'] = \
|
||||
FingerprintWindow(self.plugin, self.contact,
|
||||
self.chat_control.parent_win.window,
|
||||
self.windowinstances)
|
||||
self.windowinstances['dialog'].show_all()
|
||||
if fingerprints:
|
||||
log.debug(self.account +
|
||||
@@ -225,10 +298,12 @@ class Ui(object):
|
||||
|
||||
def no_trusted_fingerprints_warning(self):
|
||||
msg = "To send an encrypted message, you have to " \
|
||||
"first trust the fingerprint of your contact!"
|
||||
"first trust the fingerprint of your contact!"
|
||||
self.chat_control.print_conversation_line(msg, 'status', '', None)
|
||||
|
||||
def refresh_auth_lock_icon(self):
|
||||
if self.groupchat:
|
||||
return
|
||||
if self.encryption_active():
|
||||
if self.state.getUndecidedFingerprints(self.contact.jid):
|
||||
self.chat_control._show_lock_image(True, 'OMEMO', True, True,
|
||||
@@ -242,6 +317,8 @@ class Ui(object):
|
||||
|
||||
def removeUi(self):
|
||||
self.actions_hbox.remove(self.omemobutton)
|
||||
self.chat_control._show_lock_image(False, 'OMEMO', False, True,
|
||||
False)
|
||||
self.chat_control.prepare_context_menu = \
|
||||
self.chat_control.omemo_orig_prepare_context_menu
|
||||
self.chat_control.send_message = self.chat_control.orig_send_message
|
||||
@@ -256,40 +333,144 @@ class OMEMOConfigDialog(GajimPluginConfigDialog):
|
||||
self.B.set_translation_domain('gajim_plugins')
|
||||
self.B.add_from_file(self.GTK_BUILDER_FILE_PATH)
|
||||
|
||||
self.fpr_model = Gtk.ListStore(GObject.TYPE_INT,
|
||||
GObject.TYPE_STRING,
|
||||
GObject.TYPE_STRING,
|
||||
GObject.TYPE_STRING)
|
||||
try:
|
||||
self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS']
|
||||
except KeyError:
|
||||
self.plugin.config['DISABLED_ACCOUNTS'] = []
|
||||
self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS']
|
||||
|
||||
self.device_model = Gtk.ListStore(GObject.TYPE_INT)
|
||||
log.debug('Disabled Accounts:')
|
||||
log.debug(self.disabled_accounts)
|
||||
|
||||
self.account_store = self.B.get_object('account_store')
|
||||
|
||||
for account in sorted(gajim.contacts.get_accounts()):
|
||||
self.account_store.append(row=(account,))
|
||||
self.fpr_model = self.B.get_object('fingerprint_store')
|
||||
self.device_model = self.B.get_object('deviceid_store')
|
||||
|
||||
self.fpr_view = self.B.get_object('fingerprint_view')
|
||||
self.fpr_view.set_model(self.fpr_model)
|
||||
self.fpr_view.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
|
||||
|
||||
self.device_view = self.B.get_object('deviceid_view')
|
||||
self.device_view.set_model(self.device_model)
|
||||
self.disabled_acc_store = self.B.get_object('disabled_account_store')
|
||||
self.account_store = self.B.get_object('account_store')
|
||||
|
||||
if len(self.account_store) > 0:
|
||||
self.B.get_object('account_combobox').set_active(0)
|
||||
self.active_acc_view = self.B.get_object('active_accounts_view')
|
||||
self.disabled_acc_view = self.B.get_object('disabled_accounts_view')
|
||||
|
||||
vbox = self.get_content_area()
|
||||
vbox.pack_start(self.B.get_object('notebook1'), True, True, 0)
|
||||
|
||||
self.B.connect_signals(self)
|
||||
|
||||
self.plugin_active = False
|
||||
|
||||
def on_run(self):
|
||||
self.update_context_list()
|
||||
self.account_combobox_changed_cb(self.B.get_object('account_combobox'))
|
||||
for plugin in gajim.plugin_manager.active_plugins:
|
||||
log.debug(type(plugin))
|
||||
if type(plugin).__name__ == 'OmemoPlugin':
|
||||
self.plugin_active = True
|
||||
break
|
||||
self.update_account_store()
|
||||
self.update_account_combobox()
|
||||
self.update_disabled_account_view()
|
||||
|
||||
def is_in_accountstore(self, account):
|
||||
for row in self.account_store:
|
||||
if row[0] == account:
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_account_store(self):
|
||||
for account in sorted(gajim.contacts.get_accounts()):
|
||||
if account not in self.disabled_accounts and \
|
||||
not self.is_in_accountstore(account):
|
||||
self.account_store.append(row=(account,))
|
||||
|
||||
def update_account_combobox(self):
|
||||
if self.plugin_active is False:
|
||||
return
|
||||
if len(self.account_store) > 0:
|
||||
self.B.get_object('account_combobox').set_active(0)
|
||||
else:
|
||||
self.account_combobox_changed_cb(
|
||||
self.B.get_object('account_combobox'))
|
||||
|
||||
def account_combobox_changed_cb(self, box, *args):
|
||||
self.update_context_list()
|
||||
|
||||
def get_qrcode(self, jid, sid, fingerprint):
|
||||
file_name = 'omemo_{}.png'.format(jid)
|
||||
path = os.path.join(
|
||||
configpaths.gajimpaths['MY_DATA'], file_name)
|
||||
|
||||
ver_string = 'xmpp:{}?omemo-sid-{}={}'.format(jid, sid, fingerprint)
|
||||
log.debug('Verification String: ' + ver_string)
|
||||
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
qr = qrcode.QRCode(version=None, error_correction=2, box_size=4, border=1)
|
||||
qr.add_data(ver_string)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image()
|
||||
img.save(path)
|
||||
return path
|
||||
|
||||
def update_disabled_account_view(self):
|
||||
self.disabled_acc_store.clear()
|
||||
for account in self.disabled_accounts:
|
||||
self.disabled_acc_store.append(row=(account,))
|
||||
|
||||
def activate_accounts_btn_clicked(self, button, *args):
|
||||
mod, paths = self.disabled_acc_view.get_selection().get_selected_rows()
|
||||
for path in paths:
|
||||
it = mod.get_iter(path)
|
||||
account = mod.get(it, 0)
|
||||
if account[0] in self.disabled_accounts and \
|
||||
not self.is_in_accountstore(account[0]):
|
||||
self.account_store.append(row=(account[0],))
|
||||
self.disabled_accounts.remove(account[0])
|
||||
self.update_disabled_account_view()
|
||||
self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts
|
||||
self.update_account_combobox()
|
||||
|
||||
def disable_accounts_btn_clicked(self, button, *args):
|
||||
mod, paths = self.active_acc_view.get_selection().get_selected_rows()
|
||||
for path in paths:
|
||||
it = mod.get_iter(path)
|
||||
account = mod.get(it, 0)
|
||||
if account[0] not in self.disabled_accounts and \
|
||||
self.is_in_accountstore(account[0]):
|
||||
self.disabled_accounts.append(account[0])
|
||||
self.account_store.remove(it)
|
||||
self.update_disabled_account_view()
|
||||
self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts
|
||||
self.update_account_combobox()
|
||||
|
||||
def delfpr_button_clicked(self, button, *args):
|
||||
active = self.B.get_object('account_combobox').get_active()
|
||||
account = self.account_store[active][0]
|
||||
|
||||
state = self.plugin.get_omemo_state(account)
|
||||
|
||||
mod, paths = self.fpr_view.get_selection().get_selected_rows()
|
||||
|
||||
def on_yes(checked):
|
||||
record = state.store.loadSession(jid, deviceid)
|
||||
identity_key = record.getSessionState().getRemoteIdentityKey()
|
||||
|
||||
state.store.deleteSession(jid, deviceid)
|
||||
state.store.deleteIdentity(jid, identity_key)
|
||||
self.update_context_list()
|
||||
|
||||
for path in paths:
|
||||
it = mod.get_iter(path)
|
||||
jid, fpr, deviceid = mod.get(it, 1, 3, 4)
|
||||
fpr = fpr[31:-12]
|
||||
|
||||
YesNoDialog(
|
||||
'Delete Fingerprint?',
|
||||
'Do you want to delete the '
|
||||
'fingerprint of <b>{}</b> on your account <b>{}</b>?'
|
||||
'\n\n<tt>{}</tt>'.format(jid, account, fpr),
|
||||
on_response_yes=on_yes, transient_for=self)
|
||||
|
||||
def trust_button_clicked_cb(self, button, *args):
|
||||
active = self.B.get_object('account_combobox').get_active()
|
||||
account = self.account_store[active][0]
|
||||
@@ -298,43 +479,42 @@ class OMEMOConfigDialog(GajimPluginConfigDialog):
|
||||
|
||||
mod, paths = self.fpr_view.get_selection().get_selected_rows()
|
||||
|
||||
def on_yes(checked, identity_key):
|
||||
state.store.setTrust(identity_key, TRUSTED)
|
||||
try:
|
||||
if self.plugin.ui_list[account]:
|
||||
self.plugin.ui_list[account][jid]. \
|
||||
refresh_auth_lock_icon()
|
||||
except:
|
||||
log.debug('UI not available')
|
||||
self.update_context_list()
|
||||
|
||||
def on_no(identity_key):
|
||||
state.store.setTrust(identity_key, UNTRUSTED)
|
||||
try:
|
||||
if jid in self.plugin.ui_list[account]:
|
||||
self.plugin.ui_list[account][jid]. \
|
||||
refresh_auth_lock_icon()
|
||||
except:
|
||||
log.debug('UI not available')
|
||||
self.update_context_list()
|
||||
|
||||
for path in paths:
|
||||
it = mod.get_iter(path)
|
||||
_id, user, fpr = mod.get(it, 0, 1, 3)
|
||||
jid, fpr, deviceid = mod.get(it, 1, 3, 4)
|
||||
fpr = fpr[31:-12]
|
||||
dlg = Gtk.Dialog('Trust / Revoke Fingerprint', self,
|
||||
Gtk.DialogFlags.MODAL |
|
||||
Gtk.DialogFlags.DESTROY_WITH_PARENT,
|
||||
(Gtk.STOCK_YES, Gtk.ResponseType.YES,
|
||||
Gtk.STOCK_NO, Gtk.ResponseType.NO))
|
||||
l = Gtk.Label()
|
||||
l.set_markup('Do you want to trust the '
|
||||
'fingerprint of <b>%s</b> on your account <b>%s</b>?'
|
||||
'\n\n<tt>%s</tt>' % (user, account, fpr))
|
||||
l.set_line_wrap(True)
|
||||
l.set_padding(12, 12)
|
||||
vbox = dlg.get_content_area()
|
||||
vbox.add(l)
|
||||
dlg.show_all()
|
||||
|
||||
response = dlg.run()
|
||||
if response == Gtk.ResponseType.YES:
|
||||
state.store.identityKeyStore.setTrust(_id, TRUSTED)
|
||||
try:
|
||||
if self.plugin.ui_list[account]:
|
||||
self.plugin.ui_list[account][user].refresh_auth_lock_icon()
|
||||
except:
|
||||
dlg.destroy()
|
||||
else:
|
||||
if response == Gtk.ResponseType.NO:
|
||||
state.store.identityKeyStore.setTrust(_id, UNTRUSTED)
|
||||
try:
|
||||
if user in self.plugin.ui_list[account]:
|
||||
self.plugin.ui_list[account][user].refresh_auth_lock_icon()
|
||||
except:
|
||||
dlg.destroy()
|
||||
record = state.store.loadSession(jid, deviceid)
|
||||
identity_key = record.getSessionState().getRemoteIdentityKey()
|
||||
|
||||
self.update_context_list()
|
||||
YesNoDialog(
|
||||
'Trust / Revoke Fingerprint?',
|
||||
'Do you want to trust the fingerprint of <b>{}</b> '
|
||||
'on your account <b>{}</b>?\n\n'
|
||||
'<tt>{}</tt>'.format(jid, account, fpr),
|
||||
on_response_yes=(on_yes, identity_key),
|
||||
on_response_no=(on_no, identity_key),
|
||||
transient_for=self)
|
||||
|
||||
def cleardevice_button_clicked_cb(self, button, *args):
|
||||
active = self.B.get_object('account_combobox').get_active()
|
||||
@@ -380,67 +560,94 @@ class OMEMOConfigDialog(GajimPluginConfigDialog):
|
||||
def update_context_list(self):
|
||||
self.fpr_model.clear()
|
||||
self.device_model.clear()
|
||||
self.qrcode = self.B.get_object('qrcode')
|
||||
self.qrinfo = self.B.get_object('qrinfo')
|
||||
if len(self.account_store) == 0:
|
||||
self.B.get_object('ID').set_markup('')
|
||||
self.B.get_object('fingerprint_label').set_markup('')
|
||||
self.B.get_object('trust_button').set_sensitive(False)
|
||||
self.B.get_object('delfprbutton').set_sensitive(False)
|
||||
self.B.get_object('refresh').set_sensitive(False)
|
||||
self.B.get_object('cleardevice_button').set_sensitive(False)
|
||||
self.B.get_object('qrcode').clear()
|
||||
return
|
||||
active = self.B.get_object('account_combobox').get_active()
|
||||
account = self.account_store[active][0]
|
||||
state = self.plugin.get_omemo_state(account)
|
||||
|
||||
# Set buttons active
|
||||
self.B.get_object('trust_button').set_sensitive(True)
|
||||
self.B.get_object('delfprbutton').set_sensitive(True)
|
||||
self.B.get_object('refresh').set_sensitive(True)
|
||||
if account == 'Local':
|
||||
self.B.get_object('cleardevice_button').set_sensitive(False)
|
||||
else:
|
||||
self.B.get_object('cleardevice_button').set_sensitive(True)
|
||||
|
||||
# Set FPR Label and DeviceID
|
||||
state = self.plugin.get_omemo_state(account)
|
||||
deviceid = state.own_device_id
|
||||
self.B.get_object('ID').set_markup('<tt>%s</tt>' % deviceid)
|
||||
|
||||
ownfpr = binascii.hexlify(state.store.getIdentityKeyPair()
|
||||
.getPublicKey().serialize()).decode('utf-8')
|
||||
ownfpr = self.human_hash(ownfpr[2:])
|
||||
human_ownfpr = human_hash(ownfpr[2:])
|
||||
self.B.get_object('fingerprint_label').set_markup('<tt>%s</tt>'
|
||||
% ownfpr)
|
||||
% human_ownfpr)
|
||||
|
||||
fprDB = state.store.identityKeyStore.getAllFingerprints()
|
||||
activeSessions = state.store.sessionStore. \
|
||||
getAllActiveSessionsKeys()
|
||||
for item in fprDB:
|
||||
_id, jid, fpr, tr = item
|
||||
active = fpr in activeSessions
|
||||
fpr = binascii.hexlify(fpr).decode('utf-8')
|
||||
fpr = self.human_hash(fpr[2:])
|
||||
jid = jid.decode('utf-8')
|
||||
if tr == UNTRUSTED:
|
||||
if active:
|
||||
self.fpr_model.append((_id, jid, 'False',
|
||||
'<tt><span foreground="#FF0040">%s</span></tt>' % fpr))
|
||||
else:
|
||||
self.fpr_model.append((_id, jid, 'False',
|
||||
'<tt><span foreground="#585858">%s</span></tt>' % fpr))
|
||||
elif tr == TRUSTED:
|
||||
if active:
|
||||
self.fpr_model.append((_id, jid, 'True',
|
||||
'<tt><span foreground="#2EFE2E">%s</span></tt>' % fpr))
|
||||
else:
|
||||
self.fpr_model.append((_id, jid, 'True',
|
||||
'<tt><span foreground="#585858">%s</span></tt>' % fpr))
|
||||
else:
|
||||
if active:
|
||||
self.fpr_model.append((_id, jid, 'Undecided',
|
||||
'<tt><span foreground="#FF8000">%s</span></tt>' % fpr))
|
||||
else:
|
||||
self.fpr_model.append((_id, jid, 'Undecided',
|
||||
'<tt><span foreground="#585858">%s</span></tt>' % fpr))
|
||||
# Set Fingerprint List
|
||||
trust_str = {0: 'False', 1: 'True', 2: 'Undecided'}
|
||||
session_db = state.store.getAllSessions()
|
||||
|
||||
for item in session_db:
|
||||
color = {0: '#FF0040', # red
|
||||
1: '#2EFE2E', # green
|
||||
2: '#FF8000'} # orange
|
||||
|
||||
_id, jid, deviceid, record, active = item
|
||||
|
||||
active = bool(active)
|
||||
|
||||
identity_key = SessionRecord(serialized=record). \
|
||||
getSessionState().getRemoteIdentityKey()
|
||||
fpr = binascii.hexlify(
|
||||
identity_key.getPublicKey().serialize()).decode('utf-8')
|
||||
fpr = human_hash(fpr[2:])
|
||||
|
||||
trust = state.store.isTrustedIdentity(jid, identity_key)
|
||||
|
||||
if not active:
|
||||
color[trust] = '#585858' # grey
|
||||
|
||||
self.fpr_model.append(
|
||||
(_id, jid, trust_str[trust],
|
||||
'<tt><span foreground="{}">{}</span></tt>'.
|
||||
format(color[trust], fpr),
|
||||
deviceid))
|
||||
|
||||
# Set Device ID List
|
||||
for item in state.own_devices:
|
||||
self.device_model.append([item])
|
||||
|
||||
def human_hash(self, fpr):
|
||||
fpr = fpr.upper()
|
||||
fplen = len(fpr)
|
||||
wordsize = fplen // 8
|
||||
buf = ''
|
||||
for w in range(0, fplen, wordsize):
|
||||
buf += '{0} '.format(fpr[w:w + wordsize])
|
||||
return buf.rstrip()
|
||||
# Set QR Verification Code
|
||||
if PILLOW:
|
||||
path = self.get_qrcode(
|
||||
gajim.get_jid_from_account(account), deviceid, ownfpr[2:])
|
||||
self.qrcode.set_from_pixbuf(GdkPixbuf.Pixbuf.new_from_file(path))
|
||||
self.qrinfo.hide()
|
||||
else:
|
||||
self.qrinfo.show()
|
||||
|
||||
|
||||
class FingerprintWindow(Gtk.Dialog):
|
||||
def __init__(self, plugin, contact, parent, windowinstances):
|
||||
def __init__(self, plugin, contact, parent, windowinstances,
|
||||
groupchat=False):
|
||||
self.groupchat = groupchat
|
||||
self.contact = contact
|
||||
self.windowinstances = windowinstances
|
||||
self.account = self.contact.account.name
|
||||
self.plugin = plugin
|
||||
self.omemostate = self.plugin.get_omemo_state(self.account)
|
||||
self.own_jid = gajim.get_jid_from_account(self.account)
|
||||
Gtk.Dialog.__init__(self,
|
||||
title=('Fingerprints for %s') % contact.jid,
|
||||
parent=parent,
|
||||
@@ -448,45 +655,34 @@ class FingerprintWindow(Gtk.Dialog):
|
||||
close_button = self.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
|
||||
close_button.connect('clicked', self.on_close_button_clicked)
|
||||
self.connect('delete-event', self.on_window_delete)
|
||||
self.plugin = plugin
|
||||
|
||||
self.GTK_BUILDER_FILE_PATH = \
|
||||
self.plugin.local_file_path('fpr_dialog.ui')
|
||||
self.B = Gtk.Builder()
|
||||
self.B.set_translation_domain('gajim_plugins')
|
||||
self.B.add_from_file(self.GTK_BUILDER_FILE_PATH)
|
||||
self.xml = Gtk.Builder()
|
||||
self.xml.add_from_file(self.GTK_BUILDER_FILE_PATH)
|
||||
self.xml.set_translation_domain('gajim_plugins')
|
||||
|
||||
self.fpr_model = Gtk.ListStore(GObject.TYPE_INT,
|
||||
GObject.TYPE_STRING,
|
||||
GObject.TYPE_STRING,
|
||||
GObject.TYPE_STRING)
|
||||
self.fpr_model = self.xml.get_object('fingerprint_store')
|
||||
|
||||
self.fpr_view = self.B.get_object('fingerprint_view')
|
||||
self.fpr_view.set_model(self.fpr_model)
|
||||
self.fpr_view.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
|
||||
|
||||
self.fpr_view_own = self.B.get_object('fingerprint_view_own')
|
||||
self.fpr_view_own.set_model(self.fpr_model)
|
||||
self.fpr_view_own.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
|
||||
|
||||
self.notebook = self.B.get_object('notebook1')
|
||||
self.fpr_view = self.xml.get_object('fingerprint_view')
|
||||
self.fpr_view_own = self.xml.get_object('fingerprint_view_own')
|
||||
|
||||
self.notebook = self.xml.get_object('notebook1')
|
||||
vbox = self.get_content_area()
|
||||
vbox.pack_start(self.notebook, True, True, 0)
|
||||
|
||||
self.B.connect_signals(self)
|
||||
|
||||
self.account = self.contact.account.name
|
||||
self.omemostate = self.plugin.get_omemo_state(self.account)
|
||||
self.xml.connect_signals(self)
|
||||
|
||||
# Set own Fingerprint Label
|
||||
ownfpr = binascii.hexlify(self.omemostate.store.getIdentityKeyPair()
|
||||
.getPublicKey().serialize()).decode('utf-8')
|
||||
ownfpr = self.human_hash(ownfpr[2:])
|
||||
|
||||
self.B.get_object('fingerprint_label_own').set_markup('<tt>%s</tt>'
|
||||
% ownfpr)
|
||||
|
||||
ownfpr = human_hash(ownfpr[2:])
|
||||
self.xml.get_object('fingerprint_label_own').set_markup('<tt>%s</tt>'
|
||||
% ownfpr)
|
||||
self.update_context_list()
|
||||
|
||||
self.show_all()
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
del self.windowinstances['dialog']
|
||||
self.hide()
|
||||
@@ -496,43 +692,43 @@ class FingerprintWindow(Gtk.Dialog):
|
||||
self.hide()
|
||||
|
||||
def trust_button_clicked_cb(self, button, *args):
|
||||
state = self.omemostate
|
||||
|
||||
if self.notebook.get_current_page() == 1:
|
||||
mod, paths = self.fpr_view_own.get_selection().get_selected_rows()
|
||||
else:
|
||||
mod, paths = self.fpr_view.get_selection().get_selected_rows()
|
||||
|
||||
for path in paths:
|
||||
it = mod.get_iter(path)
|
||||
_id, user, fpr = mod.get(it, 0, 1, 3)
|
||||
fpr = fpr[31:-12]
|
||||
dlg = Gtk.Dialog('Trust / Revoke Fingerprint', self,
|
||||
Gtk.DialogFlags.MODAL |
|
||||
Gtk.DialogFlags.DESTROY_WITH_PARENT,
|
||||
(Gtk.STOCK_YES, Gtk.ResponseType.YES,
|
||||
Gtk.STOCK_NO, Gtk.ResponseType.NO))
|
||||
l = Gtk.Label()
|
||||
l.set_markup('Do you want to trust the '
|
||||
'fingerprint of <b>%s</b> on your account <b>%s</b>?'
|
||||
'\n\n<tt>%s</tt>' % (user, self.account, fpr))
|
||||
l.set_line_wrap(True)
|
||||
l.set_padding(12, 12)
|
||||
vbox = dlg.get_content_area()
|
||||
vbox.add(l)
|
||||
dlg.show_all()
|
||||
response = dlg.run()
|
||||
if response == Gtk.ResponseType.YES:
|
||||
self.omemostate.store.identityKeyStore.setTrust(_id, TRUSTED)
|
||||
def on_yes(checked, identity_key):
|
||||
state.store.setTrust(identity_key, TRUSTED)
|
||||
if not self.groupchat:
|
||||
self.plugin.ui_list[self.account][self.contact.jid]. \
|
||||
refresh_auth_lock_icon()
|
||||
dlg.destroy()
|
||||
else:
|
||||
if response == Gtk.ResponseType.NO:
|
||||
self.omemostate.store.identityKeyStore.setTrust(_id, UNTRUSTED)
|
||||
self.plugin.ui_list[self.account][self.contact.jid]. \
|
||||
refresh_auth_lock_icon()
|
||||
dlg.destroy()
|
||||
self.update_context_list()
|
||||
|
||||
self.update_context_list()
|
||||
def on_no(identity_key):
|
||||
state.store.setTrust(identity_key, UNTRUSTED)
|
||||
if not self.groupchat:
|
||||
self.plugin.ui_list[self.account][self.contact.jid]. \
|
||||
refresh_auth_lock_icon()
|
||||
self.update_context_list()
|
||||
|
||||
for path in paths:
|
||||
it = mod.get_iter(path)
|
||||
jid, fpr, deviceid = mod.get(it, 1, 3, 4)
|
||||
fpr = fpr[31:-12]
|
||||
|
||||
record = state.store.loadSession(jid, deviceid)
|
||||
identity_key = record.getSessionState().getRemoteIdentityKey()
|
||||
|
||||
YesNoDialog(
|
||||
'Trust / Revoke Fingerprint?',
|
||||
'Do you want to trust the fingerprint of <b>{}</b> '
|
||||
'on your account <b>{}</b>?\n\n'
|
||||
'<tt>{}</tt>'.format(jid, self.account, fpr),
|
||||
on_response_yes=(on_yes, identity_key),
|
||||
on_response_no=(on_no, identity_key),
|
||||
transient_for=self)
|
||||
|
||||
def fpr_button_pressed_cb(self, tw, event):
|
||||
if event.button == 3:
|
||||
@@ -547,7 +743,7 @@ class FingerprintWindow(Gtk.Dialog):
|
||||
# selection, otherwise we only select the new item
|
||||
keep_selection = tw.get_selection().path_is_selected(pthinfo[0])
|
||||
|
||||
pop = self.B.get_object('fprclipboard_menu')
|
||||
pop = self.xml.get_object('fprclipboard_menu')
|
||||
pop.popup(None, None, None, event.button, event.time)
|
||||
|
||||
# keep_selection=True -> no further processing of click event
|
||||
@@ -571,49 +767,56 @@ class FingerprintWindow(Gtk.Dialog):
|
||||
|
||||
def update_context_list(self, *args):
|
||||
self.fpr_model.clear()
|
||||
state = self.omemostate
|
||||
|
||||
if self.notebook.get_current_page() == 1:
|
||||
jid = gajim.get_jid_from_account(self.account)
|
||||
contact_jid = self.own_jid
|
||||
else:
|
||||
jid = self.contact.jid
|
||||
contact_jid = self.contact.jid
|
||||
|
||||
fprDB = self.omemostate.store.identityKeyStore.getFingerprints(jid)
|
||||
activeSessions = self.omemostate.store.sessionStore. \
|
||||
getActiveSessionsKeys(jid)
|
||||
trust_str = {0: 'False', 1: 'True', 2: 'Undecided'}
|
||||
if self.groupchat and self.notebook.get_current_page() == 0:
|
||||
contact_jids = []
|
||||
for nick in self.plugin.groupchat[contact_jid]:
|
||||
real_jid = self.plugin.groupchat[contact_jid][nick]
|
||||
if real_jid == self.own_jid:
|
||||
continue
|
||||
contact_jids.append(real_jid)
|
||||
session_db = state.store.getSessionsFromJids(contact_jids)
|
||||
else:
|
||||
session_db = state.store.getSessionsFromJid(contact_jid)
|
||||
|
||||
for item in fprDB:
|
||||
_id, jid, fpr, tr = item
|
||||
active = fpr in activeSessions
|
||||
fpr = binascii.hexlify(fpr).decode('utf-8')
|
||||
fpr = self.human_hash(fpr[2:])
|
||||
jid = jid.decode('utf-8')
|
||||
if tr == UNTRUSTED:
|
||||
if active:
|
||||
self.fpr_model.append((_id, jid, 'False',
|
||||
'<tt><span foreground="#FF0040">%s</span></tt>' % fpr))
|
||||
else:
|
||||
self.fpr_model.append((_id, jid, 'False',
|
||||
'<tt><span foreground="#585858">%s</span></tt>' % fpr))
|
||||
elif tr == TRUSTED:
|
||||
if active:
|
||||
self.fpr_model.append((_id, jid, 'True',
|
||||
'<tt><span foreground="#2EFE2E">%s</span></tt>' % fpr))
|
||||
else:
|
||||
self.fpr_model.append((_id, jid, 'True',
|
||||
'<tt><span foreground="#585858">%s</span></tt>' % fpr))
|
||||
else:
|
||||
if active:
|
||||
self.fpr_model.append((_id, jid, 'Undecided',
|
||||
'<tt><span foreground="#FF8000">%s</span></tt>' % fpr))
|
||||
else:
|
||||
self.fpr_model.append((_id, jid, 'Undecided',
|
||||
'<tt><span foreground="#585858">%s</span></tt>' % fpr))
|
||||
for item in session_db:
|
||||
color = {0: '#FF0040', # red
|
||||
1: '#2EFE2E', # green
|
||||
2: '#FF8000'} # orange
|
||||
|
||||
def human_hash(self, fpr):
|
||||
fpr = fpr.upper()
|
||||
fplen = len(fpr)
|
||||
wordsize = fplen // 8
|
||||
buf = ''
|
||||
for w in range(0, fplen, wordsize):
|
||||
buf += '{0} '.format(fpr[w:w + wordsize])
|
||||
return buf.rstrip()
|
||||
_id, jid, deviceid, record, active = item
|
||||
|
||||
active = bool(active)
|
||||
|
||||
identity_key = SessionRecord(serialized=record). \
|
||||
getSessionState().getRemoteIdentityKey()
|
||||
fpr = binascii.hexlify(identity_key.getPublicKey().serialize()).decode('utf-8')
|
||||
fpr = human_hash(fpr[2:])
|
||||
|
||||
trust = state.store.isTrustedIdentity(jid, identity_key)
|
||||
|
||||
if not active:
|
||||
color[trust] = '#585858' # grey
|
||||
|
||||
self.fpr_model.append(
|
||||
(_id, jid, trust_str[trust],
|
||||
'<tt><span foreground="{}">{}</span></tt>'.
|
||||
format(color[trust], fpr),
|
||||
deviceid))
|
||||
|
||||
|
||||
def human_hash(fpr):
|
||||
fpr = fpr.upper()
|
||||
fplen = len(fpr)
|
||||
wordsize = fplen // 8
|
||||
buf = ''
|
||||
for w in range(0, fplen, wordsize):
|
||||
buf += '{0} '.format(fpr[w:w + wordsize])
|
||||
return buf.rstrip()
|
||||
|
||||
Reference in New Issue
Block a user