1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
from gpg import gnupg
from xml.etree import cElementTree as ET
import xml.sax.saxutils
from plugin import BasePlugin
import logging
log = logging.getLogger(__name__)
NS_SIGNED = "jabber:x:signed"
NS_ENCRYPTED = "jabber:x:encrypted"
class Plugin(BasePlugin):
def init(self):
self.contacts = {}
# a dict of {full-JID: 'signed'/'valid'/'invalid'}
# Whenever we receive a signed presence from a JID, we add it to this
# dict, this way we know if we can encrypt the messages we will send to
# this JID.
# If that resource sends a non-signed presence, then we remove it
# from that dict and stop encrypting our messages.
self.gpg = gnupg.GPG()
self.keyid = self.config.get('keyid', '') or None
self.passphrase = self.config.get('passphrase', '') or None
if not self.keyid:
self.core.information('No GPG keyid provided in the configuration', 'Warning')
self.add_event_handler('send_normal_presence', self.sign_presence)
self.add_event_handler('normal_presence', self.on_normal_presence)
def cleanup(self):
self.send_unsigned_presence()
def sign_presence(self, presence):
"""
Sign every normal presence we send
"""
signed_element = ET.Element('{%s}x' % (NS_SIGNED))
t = self.gpg.sign(presence['status'], keyid=self.keyid, passphrase=self.passphrase)
if not t:
self.core.information('Could not sign presence. Disabling GPG module', 'Info')
self.core.plugin_manager.unload('gpg')
return
signed_element.text = xml.sax.saxutils.escape(str(t))
presence.append(signed_element)
def send_unsigned_presence(self):
"""
Send our current presence, to everyone, but unsigned, to indicate
that we cannot/do not want to encrypt/unencrypt messages.
"""
current_presence = self.core.get_status()
self.core.command_status('%s %s' % (current_presence.show or 'available', current_presence.message,))
def on_normal_presence(self, presence, resource):
"""
Check if it’s signed, if it is and we can verify the signature,
add 'valid' or 'invalid' into the dict. If it cannot be verified, just add
'signed'. Otherwise, do nothing.
"""
signed = presence.find('{%s}x' % (NS_SIGNED,))
bare = presence['from'].bare
full = presence['from'].full
if signed is None:
log.debug('Not signed')
if bare in self.contacts.keys():
del self.contacts[bare]
return
if self.config.has_section('keys') and bare in self.config.options('keys'):
verify = self.gpg.verify(signed.text)
if verify:
self.contacts[full] = 'valid'
else:
self.contacts[full] = 'invalid'
else:
self.contacts[full] = 'signed'
|