fsmonitor: silence pylint warnings
[git-cola.git] / cola / gravatar.py
blobc5a53b48a801ada3e3cee6ae1112242c11284625
1 import time
2 import hashlib
4 from qtpy import QtCore
5 from qtpy import QtGui
6 from qtpy import QtWidgets
7 from qtpy import QtNetwork
9 from . import compat
10 from . import core
11 from . import icons
12 from . import qtutils
13 from .compat import parse
14 from .models import prefs
15 from .widgets import defs
18 class Gravatar:
19 @staticmethod
20 def url_for_email(email, imgsize):
21 email_hash = md5_hexdigest(email)
22 # Python2.6 requires byte strings for urllib2.quote() so we have
23 # to force
24 default_url = 'https://git-cola.github.io/images/git-64x64.jpg'
25 encoded_url = parse.quote(core.encode(default_url), core.encode(''))
26 query = '?s=%d&d=%s' % (imgsize, core.decode(encoded_url))
27 url = 'https://gravatar.com/avatar/' + email_hash + query
28 return url
31 def md5_hexdigest(value):
32 """Return the md5 hexdigest for a value.
34 Used for implementing the gravatar API. Not used for security purposes.
35 """
36 encoded_value = core.encode(value)
37 result = ''
38 try:
39 result = hashlib.md5(encoded_value).hexdigest()
40 except ValueError:
41 pass
42 if not result and compat.PY_VERSION >= (3, 6):
43 try:
44 # pylint: disable=unexpected-keyword-arg
45 result = hashlib.md5(encoded_value, usedforsecurity=False).hexdigest()
46 except ValueError:
47 # https://github.com/git-cola/git-cola/issues/1157
48 # ValueError: error:060800A3:
49 # digital envelope routines: EVP_DigestInit_ex: disabled for fips
51 # Newer versions of Python, including Centos8's patched Python3.6 and
52 # mainline Python 3.9+ have a "usedoforsecurity" parameter which allows us
53 # to continue using hashlib.md5().
54 pass
55 return core.decode(result)
58 class GravatarLabel(QtWidgets.QLabel):
59 def __init__(self, context, parent=None):
60 QtWidgets.QLabel.__init__(self, parent)
62 self.context = context
63 self.email = None
64 self.response = None
65 self.timeout = 0
66 self.imgsize = defs.medium_icon
67 self.pixmaps = {}
68 self._default_pixmap_bytes = None
70 self.network = QtNetwork.QNetworkAccessManager()
71 # pylint: disable=no-member
72 self.network.finished.connect(self.network_finished)
74 def set_email(self, email):
75 """Update the author icon based on the specified email"""
76 pixmap = self.pixmaps.get(email, None)
77 if pixmap is not None:
78 self.setPixmap(pixmap)
79 return
80 if self.timeout > 0 and (int(time.time()) - self.timeout) < (5 * 60):
81 self.set_pixmap_from_response()
82 return
83 if email == self.email and self.response is not None:
84 self.set_pixmap_from_response()
85 return
86 self.email = email
87 self.request(email)
89 def request(self, email):
90 if prefs.enable_gravatar(self.context):
91 url = Gravatar.url_for_email(email, self.imgsize)
92 self.network.get(QtNetwork.QNetworkRequest(QtCore.QUrl(url)))
93 else:
94 self.pixmaps[email] = self.set_pixmap_from_response()
96 def default_pixmap_as_bytes(self):
97 if self._default_pixmap_bytes is None:
98 xres = self.imgsize
99 pixmap = icons.cola().pixmap(xres)
100 byte_array = QtCore.QByteArray()
101 buf = QtCore.QBuffer(byte_array)
102 buf.open(QtCore.QIODevice.WriteOnly)
103 pixmap.save(buf, 'PNG')
104 buf.close()
105 self._default_pixmap_bytes = byte_array
106 else:
107 byte_array = self._default_pixmap_bytes
108 return byte_array
110 def network_finished(self, reply):
111 email = self.email
113 header = QtCore.QByteArray(b'Location')
114 location = core.decode(bytes(reply.rawHeader(header))).strip()
115 if location:
116 request_location = Gravatar.url_for_email(self.email, self.imgsize)
117 relocated = location != request_location
118 else:
119 relocated = False
120 no_error = qtutils.enum_value(
121 QtNetwork.QNetworkReply.NetworkError.NoError # pylint: disable=no-member
123 if reply.error() == no_error:
124 if relocated:
125 # We could do get_url(parse.unquote(location)) to
126 # download the default image.
127 # Save bandwidth by using a pixmap.
128 self.response = self.default_pixmap_as_bytes()
129 else:
130 self.response = reply.readAll()
131 self.timeout = 0
132 else:
133 self.response = self.default_pixmap_as_bytes()
134 self.timeout = int(time.time())
136 pixmap = self.set_pixmap_from_response()
138 # If the email has not changed (e.g. no other requests)
139 # then we know that this pixmap corresponds to this specific
140 # email address. We can't blindly trust self.email else
141 # we may add cache entries for thee wrong email address.
142 url = Gravatar.url_for_email(email, self.imgsize)
143 if url == reply.url().toString():
144 self.pixmaps[email] = pixmap
146 def set_pixmap_from_response(self):
147 if self.response is None:
148 self.response = self.default_pixmap_as_bytes()
149 pixmap = QtGui.QPixmap()
150 pixmap.loadFromData(self.response)
151 self.setPixmap(pixmap)
152 return pixmap