6 """ |
6 """ |
7 Module implementing a dialog to show and edit all certificates. |
7 Module implementing a dialog to show and edit all certificates. |
8 """ |
8 """ |
9 |
9 |
10 import contextlib |
10 import contextlib |
11 |
11 import pathlib |
12 from PyQt6.QtCore import ( |
12 |
13 pyqtSlot, Qt, QByteArray, QFile, QFileInfo, QIODevice |
13 from PyQt6.QtCore import pyqtSlot, Qt, QByteArray |
14 ) |
|
15 from PyQt6.QtWidgets import QDialog, QTreeWidgetItem |
14 from PyQt6.QtWidgets import QDialog, QTreeWidgetItem |
16 with contextlib.suppress(ImportError): |
15 with contextlib.suppress(ImportError): |
17 from PyQt6.QtNetwork import QSslCertificate, QSslConfiguration, QSsl |
16 from PyQt6.QtNetwork import QSslCertificate, QSslConfiguration, QSsl |
18 |
17 |
19 from EricWidgets import EricMessageBox, EricFileDialog |
18 from EricWidgets import EricMessageBox, EricFileDialog |
217 self.tr( |
216 self.tr( |
218 """<p>The certificate <b>{0}</b> already exists.""" |
217 """<p>The certificate <b>{0}</b> already exists.""" |
219 """ Skipping.</p>""") |
218 """ Skipping.</p>""") |
220 .format(Utilities.decodeString(commonStr))) |
219 .format(Utilities.decodeString(commonStr))) |
221 else: |
220 else: |
222 pems.append(cert.toPem() + '\n') |
221 pems.append(cert.toPem() + b'\n') |
223 if server not in certificateDict: |
222 if server not in certificateDict: |
224 certificateDict[server] = QByteArray() |
223 certificateDict[server] = QByteArray() |
225 certificateDict[server].append(pems) |
224 certificateDict[server].append(pems) |
226 Preferences.getSettings().setValue( |
225 Preferences.getSettings().setValue( |
227 "Ssl/CaCertificatesDict", |
226 "Ssl/CaCertificatesDict", |
431 |
430 |
432 def __exportCertificate(self, name, cert): |
431 def __exportCertificate(self, name, cert): |
433 """ |
432 """ |
434 Private slot to export a certificate. |
433 Private slot to export a certificate. |
435 |
434 |
436 @param name default file name without extension (string) |
435 @param name default file name without extension |
437 @param cert certificate to be exported (QSslCertificate) |
436 @type str |
|
437 @param cert certificate to be exported encoded as PEM |
|
438 @type QByteArray |
438 """ |
439 """ |
439 if cert is not None: |
440 if cert is not None: |
440 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( |
441 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( |
441 self, |
442 self, |
442 self.tr("Export Certificate"), |
443 self.tr("Export Certificate"), |
445 "Certificate File (DER) (*.der)"), |
446 "Certificate File (DER) (*.der)"), |
446 None, |
447 None, |
447 EricFileDialog.DontConfirmOverwrite) |
448 EricFileDialog.DontConfirmOverwrite) |
448 |
449 |
449 if fname: |
450 if fname: |
450 ext = QFileInfo(fname).suffix() |
451 fpath = pathlib.Path(fname) |
451 if not ext or ext not in ["pem", "der"]: |
452 if not fpath.suffix: |
452 ex = selectedFilter.split("(*")[1].split(")")[0] |
453 ex = selectedFilter.split("(*")[1].split(")")[0] |
453 if ex: |
454 if ex: |
454 fname += ex |
455 fpath = fpath.with_suffix(ex) |
455 if QFileInfo(fname).exists(): |
456 if fpath.exists(): |
456 res = EricMessageBox.yesNo( |
457 res = EricMessageBox.yesNo( |
457 self, |
458 self, |
458 self.tr("Export Certificate"), |
459 self.tr("Export Certificate"), |
459 self.tr("<p>The file <b>{0}</b> already exists." |
460 self.tr("<p>The file <b>{0}</b> already exists." |
460 " Overwrite it?</p>").format(fname), |
461 " Overwrite it?</p>").format(fname), |
461 icon=EricMessageBox.Warning) |
462 icon=EricMessageBox.Warning) |
462 if not res: |
463 if not res: |
463 return |
464 return |
464 |
465 |
465 f = QFile(fname) |
466 if fpath.suffix == ".pem": |
466 if not f.open(QIODevice.OpenModeFlag.WriteOnly): |
467 crt = bytes(cert) |
|
468 else: |
|
469 crt = bytes( |
|
470 QSslCertificate.fromData( |
|
471 crt, QSsl.EncodingFormat.Pem)[0].toDer() |
|
472 ) |
|
473 try: |
|
474 with fpath.open("wb") as f: |
|
475 f.write(crt) |
|
476 except OSError as err: |
467 EricMessageBox.critical( |
477 EricMessageBox.critical( |
468 self, |
478 self, |
469 self.tr("Export Certificate"), |
479 self.tr("Export Certificate"), |
470 self.tr( |
480 self.tr( |
471 """<p>The certificate could not be written""" |
481 """<p>The certificate could not be written""" |
472 """ to file <b>{0}</b></p><p>Error: {1}</p>""") |
482 """ to file <b>{0}</b></p><p>Error: {1}</p>""") |
473 .format(fname, f.errorString())) |
483 .format(str(fpath), str(err))) |
474 return |
|
475 |
|
476 if fname.endswith(".pem"): |
|
477 crt = cert.toPem() |
|
478 else: |
|
479 crt = cert.toDer() |
|
480 f.write(crt) |
|
481 f.close() |
|
482 |
484 |
483 def __importCertificate(self): |
485 def __importCertificate(self): |
484 """ |
486 """ |
485 Private method to read a certificate. |
487 Private method to read a certificate. |
486 |
488 |
487 @return certificates read (list of QSslCertificate) |
489 @return certificates read |
|
490 @rtype list of QSslCertificate |
488 """ |
491 """ |
489 fname = EricFileDialog.getOpenFileName( |
492 fname = EricFileDialog.getOpenFileName( |
490 self, |
493 self, |
491 self.tr("Import Certificate"), |
494 self.tr("Import Certificate"), |
492 "", |
495 "", |
493 self.tr("Certificate Files (*.pem *.crt *.der *.cer *.ca);;" |
496 self.tr("Certificate Files (*.pem *.crt *.der *.cer *.ca);;" |
494 "All Files (*)")) |
497 "All Files (*)")) |
495 |
498 |
496 if fname: |
499 if fname: |
497 f = QFile(fname) |
500 try: |
498 if not f.open(QIODevice.OpenModeFlag.ReadOnly): |
501 with pathlib.Path(fname).open("rb") as f: |
|
502 crt = QByteArray(f.read()) |
|
503 cert = QSslCertificate.fromData( |
|
504 crt, QSsl.EncodingFormat.Pem) |
|
505 if not cert: |
|
506 cert = QSslCertificate.fromData( |
|
507 crt, QSsl.EncodingFormat.Der) |
|
508 |
|
509 return cert |
|
510 except OSError as err: |
499 EricMessageBox.critical( |
511 EricMessageBox.critical( |
500 self, |
512 self, |
501 self.tr("Export Certificate"), |
513 self.tr("Import Certificate"), |
502 self.tr( |
514 self.tr( |
503 """<p>The certificate could not be read from file""" |
515 """<p>The certificate could not be read from file""" |
504 """ <b>{0}</b></p><p>Error: {1}</p>""") |
516 """ <b>{0}</b></p><p>Error: {1}</p>""") |
505 .format(fname, f.errorString())) |
517 .format(fname, str(err))) |
506 return [] |
|
507 |
|
508 crt = f.readAll() |
|
509 f.close() |
|
510 cert = QSslCertificate.fromData(crt, QSsl.EncodingFormat.Pem) |
|
511 if not cert: |
|
512 cert = QSslCertificate.fromData(crt, QSsl.EncodingFormat.Der) |
|
513 |
|
514 return cert |
|
515 |
518 |
516 return [] |
519 return [] |