Move compute_caps_hash from helpers to caps module.
This commit is contained in:
parent
47f875a4bc
commit
99e8487db9
|
@ -33,6 +33,8 @@ through ClientCaps objects which are hold by contact instances.
|
|||
|
||||
import gajim
|
||||
import helpers
|
||||
import base64
|
||||
import hashlib
|
||||
|
||||
from common.xmpp import NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION, NS_CHATSTATES
|
||||
# Features where we cannot safely assume that the other side supports them
|
||||
|
@ -46,6 +48,76 @@ def initialize(logger):
|
|||
capscache = CapsCache(logger)
|
||||
|
||||
|
||||
def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'):
|
||||
'''Compute caps hash according to XEP-0115, V1.5
|
||||
|
||||
dataforms are xmpp.DataForms objects as common.dataforms don't allow several
|
||||
values without a field type list-multi'''
|
||||
|
||||
def sort_identities_func(i1, i2):
|
||||
cat1 = i1['category']
|
||||
cat2 = i2['category']
|
||||
if cat1 < cat2:
|
||||
return -1
|
||||
if cat1 > cat2:
|
||||
return 1
|
||||
type1 = i1.get('type', '')
|
||||
type2 = i2.get('type', '')
|
||||
if type1 < type2:
|
||||
return -1
|
||||
if type1 > type2:
|
||||
return 1
|
||||
lang1 = i1.get('xml:lang', '')
|
||||
lang2 = i2.get('xml:lang', '')
|
||||
if lang1 < lang2:
|
||||
return -1
|
||||
if lang1 > lang2:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def sort_dataforms_func(d1, d2):
|
||||
f1 = d1.getField('FORM_TYPE')
|
||||
f2 = d2.getField('FORM_TYPE')
|
||||
if f1 and f2 and (f1.getValue() < f2.getValue()):
|
||||
return -1
|
||||
return 1
|
||||
|
||||
S = ''
|
||||
identities.sort(cmp=sort_identities_func)
|
||||
for i in identities:
|
||||
c = i['category']
|
||||
type_ = i.get('type', '')
|
||||
lang = i.get('xml:lang', '')
|
||||
name = i.get('name', '')
|
||||
S += '%s/%s/%s/%s<' % (c, type_, lang, name)
|
||||
features.sort()
|
||||
for f in features:
|
||||
S += '%s<' % f
|
||||
dataforms.sort(cmp=sort_dataforms_func)
|
||||
for dataform in dataforms:
|
||||
# fields indexed by var
|
||||
fields = {}
|
||||
for f in dataform.getChildren():
|
||||
fields[f.getVar()] = f
|
||||
form_type = fields.get('FORM_TYPE')
|
||||
if form_type:
|
||||
S += form_type.getValue() + '<'
|
||||
del fields['FORM_TYPE']
|
||||
for var in sorted(fields.keys()):
|
||||
S += '%s<' % var
|
||||
values = sorted(fields[var].getValues())
|
||||
for value in values:
|
||||
S += '%s<' % value
|
||||
|
||||
if hash_method == 'sha-1':
|
||||
hash_ = hashlib.sha1(S)
|
||||
elif hash_method == 'md5':
|
||||
hash_ = hashlib.md5(S)
|
||||
else:
|
||||
return ''
|
||||
return base64.b64encode(hash_.digest())
|
||||
|
||||
|
||||
class AbstractClientCaps(object):
|
||||
'''
|
||||
Base class representing a client and its capabilities as advertised by
|
||||
|
@ -92,7 +164,7 @@ class ClientCaps(AbstractClientCaps):
|
|||
connection.discoverInfo(jid, '%s#%s' % (self._node, self._hash))
|
||||
|
||||
def _is_hash_valid(self, identities, features, dataforms):
|
||||
computed_hash = helpers.compute_caps_hash(identities, features,
|
||||
computed_hash = compute_caps_hash(identities, features,
|
||||
dataforms=dataforms, hash_method=self._hash_method)
|
||||
return computed_hash == self._hash
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ import urllib
|
|||
import errno
|
||||
import select
|
||||
import base64
|
||||
import sys
|
||||
import hashlib
|
||||
import caps
|
||||
|
||||
from encodings.punycode import punycode_encode
|
||||
|
||||
|
@ -566,74 +566,6 @@ def datetime_tuple(timestamp):
|
|||
from time import strptime
|
||||
return strptime(timestamp, '%Y%m%dT%H:%M:%S')
|
||||
|
||||
def sort_identities_func(i1, i2):
|
||||
cat1 = i1['category']
|
||||
cat2 = i2['category']
|
||||
if cat1 < cat2:
|
||||
return -1
|
||||
if cat1 > cat2:
|
||||
return 1
|
||||
type1 = i1.get('type', '')
|
||||
type2 = i2.get('type', '')
|
||||
if type1 < type2:
|
||||
return -1
|
||||
if type1 > type2:
|
||||
return 1
|
||||
lang1 = i1.get('xml:lang', '')
|
||||
lang2 = i2.get('xml:lang', '')
|
||||
if lang1 < lang2:
|
||||
return -1
|
||||
if lang1 > lang2:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def sort_dataforms_func(d1, d2):
|
||||
f1 = d1.getField('FORM_TYPE')
|
||||
f2 = d2.getField('FORM_TYPE')
|
||||
if f1 and f2 and (f1.getValue() < f2.getValue()):
|
||||
return -1
|
||||
return 1
|
||||
|
||||
def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'):
|
||||
'''Compute caps hash according to XEP-0115, V1.5
|
||||
|
||||
dataforms are xmpp.DataForms objects as common.dataforms don't allow several
|
||||
values without a field type list-multi'''
|
||||
S = ''
|
||||
identities.sort(cmp=sort_identities_func)
|
||||
for i in identities:
|
||||
c = i['category']
|
||||
type_ = i.get('type', '')
|
||||
lang = i.get('xml:lang', '')
|
||||
name = i.get('name', '')
|
||||
S += '%s/%s/%s/%s<' % (c, type_, lang, name)
|
||||
features.sort()
|
||||
for f in features:
|
||||
S += '%s<' % f
|
||||
dataforms.sort(cmp=sort_dataforms_func)
|
||||
for dataform in dataforms:
|
||||
# fields indexed by var
|
||||
fields = {}
|
||||
for f in dataform.getChildren():
|
||||
fields[f.getVar()] = f
|
||||
form_type = fields.get('FORM_TYPE')
|
||||
if form_type:
|
||||
S += form_type.getValue() + '<'
|
||||
del fields['FORM_TYPE']
|
||||
for var in sorted(fields.keys()):
|
||||
S += '%s<' % var
|
||||
values = sorted(fields[var].getValues())
|
||||
for value in values:
|
||||
S += '%s<' % value
|
||||
|
||||
if hash_method == 'sha-1':
|
||||
hash_ = hashlib.sha1(S)
|
||||
elif hash_method == 'md5':
|
||||
hash_ = hashlib.md5(S)
|
||||
else:
|
||||
return ''
|
||||
return base64.b64encode(hash_.digest())
|
||||
|
||||
# import gajim only when needed (after decode_string is defined) see #4764
|
||||
|
||||
import gajim
|
||||
|
@ -1357,7 +1289,7 @@ def update_optional_features(account = None):
|
|||
gajim.gajim_optional_features[a].append(xmpp.NS_ESESSION)
|
||||
if gajim.config.get_per('accounts', a, 'answer_receipts'):
|
||||
gajim.gajim_optional_features[a].append(xmpp.NS_RECEIPTS)
|
||||
gajim.caps_hash[a] = compute_caps_hash([gajim.gajim_identity],
|
||||
gajim.caps_hash[a] = caps.compute_caps_hash([gajim.gajim_identity],
|
||||
gajim.gajim_common_features + gajim.gajim_optional_features[a])
|
||||
# re-send presence with new hash
|
||||
connected = gajim.connections[a].connected
|
||||
|
|
|
@ -31,6 +31,7 @@ import locale
|
|||
import re
|
||||
from common import gajim
|
||||
from common import helpers
|
||||
from common import caps
|
||||
|
||||
import exceptions
|
||||
try:
|
||||
|
@ -216,7 +217,7 @@ class OptionsParser:
|
|||
gajim.logger.init_vars()
|
||||
gajim.config.set('version', new_version)
|
||||
|
||||
gajim.capscache.initialize_from_db()
|
||||
caps.capscache.initialize_from_db()
|
||||
|
||||
def update_config_x_to_09(self):
|
||||
# Var name that changed:
|
||||
|
|
|
@ -6,8 +6,6 @@ import unittest
|
|||
import lib
|
||||
lib.setup_env()
|
||||
|
||||
from common import gajim
|
||||
from common import helpers
|
||||
from common.xmpp import NS_MUC, NS_PING, NS_XHTML_IM
|
||||
from common import caps
|
||||
from common.contacts import Contact
|
||||
|
@ -95,7 +93,7 @@ class TestCapsCache(CommonCapsTest):
|
|||
|
||||
def test_hash(self):
|
||||
'''tests the hash computation'''
|
||||
computed_hash = helpers.compute_caps_hash(self.identities, self.features)
|
||||
computed_hash = caps.compute_caps_hash(self.identities, self.features)
|
||||
self.assertEqual(self.caps_hash, computed_hash)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue