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