make esession authentication warning less obtrusive
This commit is contained in:
parent
408d3b4ff6
commit
b490904454
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--Generated with glade3 3.4.0 on Sat Jun 28 20:51:00 2008 -->
|
||||
<glade-interface>
|
||||
<widget class="GtkDialog" id="esession_info_window">
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="has_separator">False</property>
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="info_display">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">(ESession info)</property>
|
||||
<property name="wrap">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="verification_info">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="warning">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-dialog-warning</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">This contact's identity has not been verified.</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="width_chars">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="verify_now_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Verify now</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_verify_now_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Close</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_close_button_clicked"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
|
@ -111,12 +111,20 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="lock_image">
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="stock">gtk-dialog-authentication</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
<widget class="GtkButton" id="authentication_button">
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="relief">GTK_RELIEF_NONE</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="response_id">0</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="lock_image">
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-dialog-authentication</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="padding">2</property>
|
||||
|
|
|
@ -1056,6 +1056,10 @@ class ChatControl(ChatControlBase):
|
|||
self.widget_set_visible(self.xml.get_widget('banner_eventbox'),
|
||||
gajim.config.get('hide_chat_banner'))
|
||||
|
||||
self.authentication_button = self.xml.get_widget('authentication_button')
|
||||
id = self.authentication_button.connect('clicked', self._on_authentication_button_clicked)
|
||||
self.handlers[id] = self.authentication_button
|
||||
|
||||
# Add lock image to show chat encryption
|
||||
self.lock_image = self.xml.get_widget('lock_image')
|
||||
self.lock_tooltip = gtk.Tooltips()
|
||||
|
@ -1115,11 +1119,18 @@ class ChatControl(ChatControlBase):
|
|||
self.on_avatar_eventbox_button_press_event)
|
||||
self.handlers[id] = widget
|
||||
|
||||
self.session = session
|
||||
if not session:
|
||||
session = gajim.connections[self.account].find_controlless_session(self.contact.jid)
|
||||
self.session = session
|
||||
|
||||
if session:
|
||||
session.control = self
|
||||
self.session = session
|
||||
|
||||
# Enable ecryption if needed
|
||||
if session.enable_encryption:
|
||||
self.print_esession_details()
|
||||
|
||||
# Enable encryption if needed
|
||||
e2e_is_active = hasattr(self, 'session') and self.session and self.session.enable_encryption
|
||||
self.gpg_is_active = False
|
||||
gpg_pref = gajim.config.get_per('contacts', contact.jid, 'gpg_enabled')
|
||||
|
@ -1134,7 +1145,7 @@ class ChatControl(ChatControlBase):
|
|||
if self.session:
|
||||
self.session.loggable = gajim.config.get('log_encrypted_sessions')
|
||||
self._show_lock_image(self.gpg_is_active, 'GPG', self.gpg_is_active, self.session and \
|
||||
self.session.is_loggable())
|
||||
self.session.is_loggable(), self.session and self.session.verified_identity)
|
||||
|
||||
self.status_tooltip = gtk.Tooltips()
|
||||
|
||||
|
@ -1365,7 +1376,7 @@ class ChatControl(ChatControlBase):
|
|||
self.gpg_is_active)
|
||||
|
||||
self._show_lock_image(self.gpg_is_active, 'GPG', self.gpg_is_active, self.session and \
|
||||
self.session.is_loggable())
|
||||
self.session.is_loggable(), self.session and self.session.verified_identity)
|
||||
|
||||
def _show_lock_image(self, visible, enc_type = '', enc_enabled = False, chat_logged = False, authenticated = False):
|
||||
'''Set lock icon visibility and create tooltip'''
|
||||
|
@ -1373,22 +1384,26 @@ class ChatControl(ChatControlBase):
|
|||
status_string = enc_enabled and 'is' or 'is NOT'
|
||||
logged_string = chat_logged and 'will' or 'will NOT'
|
||||
|
||||
if enc_type == 'OTR':
|
||||
authenticated_string = authenticated \
|
||||
and ' and authenticated' \
|
||||
or ' and NOT authenticated'
|
||||
if authenticated:
|
||||
authenticated_string = ' and authenticated'
|
||||
self.lock_image.set_from_stock('gtk-dialog-authentication', 1)
|
||||
else:
|
||||
authenticated_string = ''
|
||||
authenticated_string = ' and NOT authenticated'
|
||||
self.lock_image.set_from_stock('gtk-dialog-warning', 1)
|
||||
|
||||
tooltip = '%s Encryption %s active%s.\n' \
|
||||
tooltip = '%s encryption %s active%s.\n' \
|
||||
'Your chat session %s be logged.' % \
|
||||
(enc_type, status_string, authenticated_string,
|
||||
(enc_type, status_string, authenticated_string,
|
||||
logged_string)
|
||||
|
||||
self.lock_tooltip.set_tip(self.lock_image, tooltip)
|
||||
self.widget_set_visible(self.lock_image, not visible)
|
||||
self.lock_tooltip.set_tip(self.authentication_button, tooltip)
|
||||
self.widget_set_visible(self.authentication_button, not visible)
|
||||
self.lock_image.set_sensitive(enc_enabled)
|
||||
|
||||
def _on_authentication_button_clicked(self, widget):
|
||||
if self.session and self.session.enable_encryption:
|
||||
dialogs.ESessionInfoWindow(self.session)
|
||||
|
||||
def _process_command(self, message):
|
||||
if message[0] != '/':
|
||||
return False
|
||||
|
@ -1588,11 +1603,15 @@ class ChatControl(ChatControlBase):
|
|||
msg = _('Session WILL NOT be logged')
|
||||
|
||||
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||
|
||||
if not self.session.verified_identity:
|
||||
ChatControlBase.print_conversation_line(self, 'SAS not verified', 'status', '', None)
|
||||
else:
|
||||
msg = _('E2E encryption disabled')
|
||||
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||
|
||||
self._show_lock_image(e2e_is_active, 'E2E', e2e_is_active, self.session and \
|
||||
self.session.is_loggable())
|
||||
self.session.is_loggable(), self.session and self.session.verified_identity)
|
||||
|
||||
def print_conversation(self, text, frm='', tim=None, encrypted=False,
|
||||
subject=None, xhtml=None, simple=False):
|
||||
|
|
|
@ -183,6 +183,9 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
# _o denotes 'other' (ie. the client at the other end of the session)
|
||||
self._kc_o = None
|
||||
|
||||
# has the remote contact's identity ever been verified?
|
||||
self.verified_identity = False
|
||||
|
||||
# keep the encrypter updated with my latest cipher key
|
||||
def set_kc_s(self, value):
|
||||
self._kc_s = value
|
||||
|
@ -338,7 +341,8 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
raise exceptions.NegotiationError, 'calculated m_%s differs from received m_%s' % (i_o, i_o)
|
||||
|
||||
if i_o == 'a' and self.sas_algs == 'sas28x5':
|
||||
# XXX not necessary if there's a verified retained secret
|
||||
# we don't need to calculate this if there's a verified retained secret
|
||||
# (but we do anyways)
|
||||
self.sas = crypto.sas_28x5(m_o, self.form_s)
|
||||
|
||||
if self.negotiated['recv_pubkey']:
|
||||
|
@ -844,26 +848,32 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
if self.control:
|
||||
self.control.print_esession_details()
|
||||
|
||||
# calculate and store the new retained secret
|
||||
# prompt the user to check the remote party's identity (if necessary)
|
||||
def do_retained_secret(self, k, srs):
|
||||
def do_retained_secret(self, k, old_srs):
|
||||
'''calculate the new retained secret. determine if the user needs to check the remote party's identity. set up callbacks for when the identity has been verified.'''
|
||||
|
||||
new_srs = self.hmac(k, 'New Retained Secret')
|
||||
self.srs = new_srs
|
||||
|
||||
account = self.conn.name
|
||||
bjid = self.jid.getStripped()
|
||||
|
||||
if srs:
|
||||
if secrets.secrets().srs_verified(account, bjid, srs):
|
||||
secrets.secrets().replace_srs(account, bjid, srs, new_srs, True)
|
||||
self.verified_identity = False
|
||||
|
||||
if old_srs:
|
||||
if secrets.secrets().srs_verified(account, bjid, old_srs):
|
||||
# already had a stored secret verified by the user.
|
||||
secrets.secrets().replace_srs(account, bjid, old_srs, new_srs, True)
|
||||
# continue without warning.
|
||||
self.verified_identity = True
|
||||
else:
|
||||
def _cb(verified):
|
||||
secrets.secrets().replace_srs(account, bjid, srs, new_srs, verified)
|
||||
|
||||
self.check_identity(_cb)
|
||||
# had a secret, but it wasn't verified.
|
||||
secrets.secrets().replace_srs(account, bjid, old_srs, new_srs, False)
|
||||
else:
|
||||
def _cb(verified):
|
||||
secrets.secrets().save_new_srs(account, bjid, new_srs, verified)
|
||||
# we don't even have an SRS
|
||||
secrets.secrets().save_new_srs(account, bjid, new_srs, False)
|
||||
|
||||
self.check_identity(_cb)
|
||||
def _verified_srs_cb(self):
|
||||
secrets.secrets().replace_srs(self.conn.name, self.jid.getStripped(), self.srs, self.srs, True)
|
||||
|
||||
def make_dhfield(self, modp_options, sigmai):
|
||||
dhs = []
|
||||
|
|
|
@ -3780,7 +3780,7 @@ class DataFormWindow(Dialog):
|
|||
self.dataform_widget.data_form = self.dataform
|
||||
self.dataform_widget.show_all()
|
||||
self.vbox.pack_start(self.dataform_widget)
|
||||
|
||||
|
||||
def on_ok(self):
|
||||
form = self.dataform_widget.data_form
|
||||
if isinstance(self.df_response_ok, tuple):
|
||||
|
@ -3788,3 +3788,42 @@ class DataFormWindow(Dialog):
|
|||
else:
|
||||
self.df_response_ok(form)
|
||||
self.destroy()
|
||||
|
||||
class ESessionInfoWindow:
|
||||
'''Class for displaying information about a XEP-0116 encrypted session'''
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
self.xml = gtkgui_helpers.get_glade('esession_info_window.glade')
|
||||
self.xml.signal_autoconnect(self)
|
||||
|
||||
self.update_info()
|
||||
|
||||
self.window = self.xml.get_widget('esession_info_window')
|
||||
self.window.show_all()
|
||||
|
||||
def update_info(self):
|
||||
labeltext = _('''Your chat session with %s is encrypted.\n\nSAS is: %s''') % (self.session.jid, self.session.sas)
|
||||
|
||||
if self.session.verified_identity:
|
||||
labeltext += '\n\n' + _('''You have already verified this contact's identity.''')
|
||||
w = self.xml.get_widget('verification_info')
|
||||
w.set_no_show_all(True)
|
||||
w.hide()
|
||||
|
||||
self.xml.get_widget('info_display').set_text(labeltext)
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
self.window.destroy()
|
||||
|
||||
def on_verify_now_button_clicked(self, widget):
|
||||
pritext = _('''Have you verified the remote contact's identity?''')
|
||||
sectext = _('''To prevent a man-in-the-middle attack, you should speak to this person directly (in person or on the phone) and verify that they see the same SAS as you.\n\nThis session's SAS: %s''') % self.session.sas
|
||||
sectext += '\n\n' + _('Did you talk to the remote contact and verify the SAS?')
|
||||
|
||||
dialog = YesNoDialog(pritext, sectext)
|
||||
|
||||
if dialog.get_response() == gtk.RESPONSE_YES:
|
||||
self.session._verified_srs_cb()
|
||||
self.session.verified_identity = True
|
||||
self.update_info()
|
||||
|
|
|
@ -14,23 +14,6 @@ def describe_features(features):
|
|||
elif features['logging'] == 'mustnot':
|
||||
return _('- messages will not be logged')
|
||||
|
||||
def show_sas_dialog(session, jid, sas, on_success):
|
||||
def success_cb(checked):
|
||||
on_success(checked)
|
||||
|
||||
def failure_cb():
|
||||
session.reject_negotiation()
|
||||
|
||||
dialogs.ConfirmationDialogCheck(_('''OK to continue with negotiation?'''),
|
||||
_('''You've begun an encrypted session with %s, but it can't be guaranteed that you're talking directly to the person you think you are.
|
||||
|
||||
You should speak with them directly (in person or on the phone) and confirm that their Short Authentication String is identical to this one: %s
|
||||
|
||||
Would you like to continue with the encrypted session?''') % (jid, sas),
|
||||
|
||||
_('Yes, I verified the Short Authentication String'),
|
||||
on_response_ok=success_cb, on_response_cancel=failure_cb, is_modal=False)
|
||||
|
||||
class FeatureNegotiationWindow:
|
||||
'''FeatureNegotiotionWindow class'''
|
||||
def __init__(self, account, jid, session, form):
|
||||
|
@ -67,8 +50,6 @@ class FeatureNegotiationWindow:
|
|||
self.window.destroy()
|
||||
|
||||
def on_cancel_button_clicked(self, widget):
|
||||
# XXX determine whether to reveal presence
|
||||
|
||||
rejection = xmpp.Message(self.jid)
|
||||
rejection.setThread(self.session.thread_id)
|
||||
feature = rejection.NT.feature
|
||||
|
@ -80,8 +61,6 @@ class FeatureNegotiationWindow:
|
|||
|
||||
feature.addChild(node=x)
|
||||
|
||||
# XXX optional <body/>
|
||||
|
||||
gajim.connections[self.account].send_stanza(rejection)
|
||||
|
||||
self.window.destroy()
|
||||
|
|
|
@ -136,7 +136,7 @@ class Secrets:
|
|||
# has the user verified this retained secret?
|
||||
def srs_verified(self, account, jid, srs):
|
||||
return self.find_srs(account, jid, srs)[1]
|
||||
|
||||
|
||||
def replace_srs(self, account, jid, old_secret, new_secret, verified):
|
||||
our_secrets = self.srs[account][jid]
|
||||
|
||||
|
|
|
@ -334,9 +334,6 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
|||
|
||||
# ---- ESessions stuff ---
|
||||
|
||||
def check_identity(self, on_success):
|
||||
negotiation.show_sas_dialog(self, self.jid, self.sas, on_success)
|
||||
|
||||
def handle_negotiation(self, form):
|
||||
if form.getField('accept') and not form['accept'] in ('1', 'true'):
|
||||
self.cancelled_negotiation()
|
||||
|
|
Loading…
Reference in New Issue