|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2010 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a widget to show SSL information. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 from PyQt5.QtCore import Qt, QUrl, QPoint |
|
13 from PyQt5.QtWidgets import QMenu, QGridLayout, QLabel, QSizePolicy |
|
14 from PyQt5.QtNetwork import QSsl, QSslConfiguration, QSslCertificate |
|
15 |
|
16 import UI.PixmapCache |
|
17 import Utilities |
|
18 from Globals import qVersionTuple |
|
19 |
|
20 |
|
21 class E5SslInfoWidget(QMenu): |
|
22 """ |
|
23 Class implementing a widget to show SSL certificate infos. |
|
24 """ |
|
25 def __init__(self, url, configuration, parent=None): |
|
26 """ |
|
27 Constructor |
|
28 |
|
29 @param url URL to show SSL info for (QUrl) |
|
30 @param configuration SSL configuration (QSslConfiguration) |
|
31 @param parent reference to the parent widget (QWidget) |
|
32 """ |
|
33 super(E5SslInfoWidget, self).__init__(parent) |
|
34 |
|
35 self.__url = QUrl(url) |
|
36 self.__configuration = QSslConfiguration(configuration) |
|
37 |
|
38 self.setMinimumWidth(400) |
|
39 |
|
40 certList = self.__configuration.peerCertificateChain() |
|
41 if certList: |
|
42 cert = certList[0] |
|
43 else: |
|
44 cert = QSslCertificate() |
|
45 |
|
46 layout = QGridLayout(self) |
|
47 rows = 0 |
|
48 |
|
49 ########################################## |
|
50 ## Identity Information |
|
51 ########################################## |
|
52 imageLabel = QLabel(self) |
|
53 layout.addWidget(imageLabel, rows, 0, Qt.AlignCenter) |
|
54 |
|
55 label = QLabel(self) |
|
56 label.setWordWrap(True) |
|
57 label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) |
|
58 label.setText(self.tr("Identity")) |
|
59 font = label.font() |
|
60 font.setBold(True) |
|
61 label.setFont(font) |
|
62 layout.addWidget(label, rows, 1) |
|
63 rows += 1 |
|
64 |
|
65 label = QLabel(self) |
|
66 label.setWordWrap(True) |
|
67 if cert.isNull(): |
|
68 label.setText(self.tr( |
|
69 "Warning: this site is NOT carrying a certificate.")) |
|
70 imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityLow32.png")) |
|
71 else: |
|
72 if qVersionTuple() >= (5, 0, 0): |
|
73 valid = not cert.isBlacklisted() |
|
74 else: |
|
75 valid = cert.isValid() |
|
76 if valid: |
|
77 if qVersionTuple() >= (5, 0, 0): |
|
78 txt = ", ".join( |
|
79 cert.issuerInfo(QSslCertificate.CommonName)) |
|
80 else: |
|
81 txt = cert.issuerInfo(QSslCertificate.CommonName) |
|
82 label.setText(self.tr( |
|
83 "The certificate for this site is valid" |
|
84 " and has been verified by:\n{0}").format( |
|
85 Utilities.decodeString(txt))) |
|
86 imageLabel.setPixmap( |
|
87 UI.PixmapCache.getPixmap("securityHigh32.png")) |
|
88 else: |
|
89 label.setText(self.tr( |
|
90 "The certificate for this site is NOT valid.")) |
|
91 imageLabel.setPixmap( |
|
92 UI.PixmapCache.getPixmap("securityLow32.png")) |
|
93 layout.addWidget(label, rows, 1) |
|
94 rows += 1 |
|
95 |
|
96 label = QLabel(self) |
|
97 label.setWordWrap(True) |
|
98 label.setText( |
|
99 '<a href="moresslinfos">' + |
|
100 self.tr("Certificate Information") + "</a>") |
|
101 label.linkActivated.connect(self.__showCertificateInfos) |
|
102 layout.addWidget(label, rows, 1) |
|
103 rows += 1 |
|
104 |
|
105 ########################################## |
|
106 ## Identity Information |
|
107 ########################################## |
|
108 imageLabel = QLabel(self) |
|
109 layout.addWidget(imageLabel, rows, 0, Qt.AlignCenter) |
|
110 |
|
111 label = QLabel(self) |
|
112 label.setWordWrap(True) |
|
113 label.setText(self.tr("Encryption")) |
|
114 font = label.font() |
|
115 font.setBold(True) |
|
116 label.setFont(font) |
|
117 layout.addWidget(label, rows, 1) |
|
118 rows += 1 |
|
119 |
|
120 cipher = self.__configuration.sessionCipher() |
|
121 if cipher.isNull(): |
|
122 label = QLabel(self) |
|
123 label.setWordWrap(True) |
|
124 label.setText(self.tr( |
|
125 'Your connection to "{0}" is NOT encrypted.\n').format( |
|
126 self.__url.host())) |
|
127 layout.addWidget(label, rows, 1) |
|
128 imageLabel.setPixmap(UI.PixmapCache.getPixmap("securityLow32.png")) |
|
129 rows += 1 |
|
130 else: |
|
131 label = QLabel(self) |
|
132 label.setWordWrap(True) |
|
133 label.setText(self.tr( |
|
134 'Your connection to "{0}" is encrypted.').format( |
|
135 self.__url.host())) |
|
136 layout.addWidget(label, rows, 1) |
|
137 |
|
138 proto = cipher.protocol() |
|
139 if proto == QSsl.SslV3: |
|
140 sslVersion = "SSL 3.0" |
|
141 imageLabel.setPixmap( |
|
142 UI.PixmapCache.getPixmap("securityLow32.png")) |
|
143 elif proto == QSsl.TlsV1SslV3: |
|
144 sslVersion = "TLS 1.0/SSL 3.0" |
|
145 imageLabel.setPixmap( |
|
146 UI.PixmapCache.getPixmap("securityLow32.png")) |
|
147 elif proto == QSsl.SslV2: |
|
148 sslVersion = "SSL 2.0" |
|
149 imageLabel.setPixmap( |
|
150 UI.PixmapCache.getPixmap("securityLow32.png")) |
|
151 else: |
|
152 sslVersion = self.tr("unknown") |
|
153 imageLabel.setPixmap( |
|
154 UI.PixmapCache.getPixmap("securityLow32.png")) |
|
155 if qVersionTuple() >= (5, 0, 0): |
|
156 if proto == QSsl.TlsV1_0: |
|
157 sslVersion = "TLS 1.0" |
|
158 imageLabel.setPixmap( |
|
159 UI.PixmapCache.getPixmap("securityHigh32.png")) |
|
160 elif proto == QSsl.TlsV1_1: |
|
161 sslVersion = "TLS 1.1" |
|
162 imageLabel.setPixmap( |
|
163 UI.PixmapCache.getPixmap("securityHigh32.png")) |
|
164 elif proto == QSsl.TlsV1_2: |
|
165 sslVersion = "TLS 1.2" |
|
166 imageLabel.setPixmap( |
|
167 UI.PixmapCache.getPixmap("securityHigh32.png")) |
|
168 else: |
|
169 if proto == QSsl.TlsV1: |
|
170 sslVersion = "TLS 1.0" |
|
171 imageLabel.setPixmap( |
|
172 UI.PixmapCache.getPixmap("securityHigh32.png")) |
|
173 rows += 1 |
|
174 |
|
175 label = QLabel(self) |
|
176 label.setWordWrap(True) |
|
177 label.setText(self.tr( |
|
178 "It uses protocol: {0}").format(sslVersion)) |
|
179 layout.addWidget(label, rows, 1) |
|
180 rows += 1 |
|
181 |
|
182 label = QLabel(self) |
|
183 label.setWordWrap(True) |
|
184 label.setText(self.tr( |
|
185 "It is encrypted using {0} at {1} bits, " |
|
186 "with {2} for message authentication and " |
|
187 "{3} as key exchange mechanism.\n\n").format( |
|
188 cipher.encryptionMethod(), |
|
189 cipher.usedBits(), |
|
190 cipher.authenticationMethod(), |
|
191 cipher.keyExchangeMethod())) |
|
192 layout.addWidget(label, rows, 1) |
|
193 rows += 1 |
|
194 |
|
195 def showAt(self, pos): |
|
196 """ |
|
197 Public method to show the widget. |
|
198 |
|
199 @param pos position to show at (QPoint) |
|
200 """ |
|
201 self.adjustSize() |
|
202 xpos = pos.x() - self.width() |
|
203 if xpos < 0: |
|
204 xpos = 10 |
|
205 p = QPoint(xpos, pos.y() + 10) |
|
206 self.move(p) |
|
207 self.show() |
|
208 |
|
209 def __showCertificateInfos(self): |
|
210 """ |
|
211 Private slot to show certificate information. |
|
212 """ |
|
213 from .E5SslCertificatesInfoDialog import E5SslCertificatesInfoDialog |
|
214 dlg = E5SslCertificatesInfoDialog( |
|
215 self.__configuration.peerCertificateChain()) |
|
216 dlg.exec_() |
|
217 |
|
218 def accept(self): |
|
219 """ |
|
220 Public method to accept the widget. |
|
221 """ |
|
222 self.close() |