File indexing completed on 2024-05-19 05:01:19
0001 /* 0002 This file is part of the KDE project. 0003 0004 SPDX-FileCopyrightText: 2021 Stefano Crocco <stefano.crocco@alice.it> 0005 0006 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0007 */ 0008 0009 #include "certificateerrordialogmanager.h" 0010 #include "webenginepage.h" 0011 #include "webenginepartcertificateerrordlg.h" 0012 #include "webengineview.h" 0013 0014 #include <algorithm> 0015 0016 0017 #include <KSharedConfig> 0018 #include <KConfigGroup> 0019 0020 using namespace KonqWebEnginePart; 0021 0022 CertificateErrorDialogManager::CertificateErrorDialogManager(QObject *parent) : QObject(parent) 0023 { 0024 } 0025 0026 CertificateErrorDialogManager::~CertificateErrorDialogManager() 0027 { 0028 } 0029 0030 bool CertificateErrorDialogManager::handleCertificateError(const QWebEngineCertificateError& _ce, WebEnginePage* page) 0031 { 0032 QWebEngineCertificateError ce(_ce); 0033 if (!ce.isOverridable()) { 0034 ce.rejectCertificate(); 0035 return false; 0036 } 0037 bool ignore = userAlreadyChoseToIgnoreError(ce); 0038 if (ignore) { 0039 #if QT_VERSION_MAJOR < 6 0040 ce.ignoreCertificateError(); 0041 #else 0042 ce.acceptCertificate(); 0043 #endif 0044 } else { 0045 ce.defer(); 0046 QPointer<WebEnginePage> ptr(page); 0047 CertificateErrorData data{ce, ptr}; 0048 if (!displayDialogIfPossible(data)) { 0049 m_certificates.append(data); 0050 } 0051 } 0052 return true; 0053 } 0054 0055 bool CertificateErrorDialogManager::userAlreadyChoseToIgnoreError(const QWebEngineCertificateError &ce) 0056 { 0057 #if QT_VERSION_MAJOR < 6 0058 int error = static_cast<int>(ce.error()); 0059 #else 0060 int error = static_cast<int>(ce.type()); 0061 #endif 0062 QString url = ce.url().url(); 0063 KConfigGroup grp(KSharedConfig::openConfig(), "CertificateExceptions"); 0064 QList<int> exceptionsForUrl = grp.readEntry(url, QList<int>{}); 0065 return (exceptionsForUrl.contains(error)); 0066 } 0067 0068 QWidget* CertificateErrorDialogManager::windowForPage(WebEnginePage* page) 0069 { 0070 if (page) { 0071 QWidget *view = page->view(); 0072 if (view) { 0073 return view->window(); 0074 } 0075 } 0076 return nullptr; 0077 } 0078 0079 bool CertificateErrorDialogManager::displayDialogIfPossible(const CertificateErrorDialogManager::CertificateErrorData& data) 0080 { 0081 QWidget *window = windowForPage(data.page); 0082 if (m_dialogs.contains(window)) { 0083 return false; 0084 } else { 0085 displayDialog(data, window); 0086 return true; 0087 } 0088 } 0089 0090 void CertificateErrorDialogManager::displayDialog(const CertificateErrorDialogManager::CertificateErrorData& data, QWidget *window) 0091 { 0092 if (!window) { 0093 window = windowForPage(data.page); 0094 } 0095 Q_ASSERT(!m_dialogs.contains(window)); 0096 0097 WebEnginePartCertificateErrorDlg *dlg = new WebEnginePartCertificateErrorDlg(data.error, data.page, window); 0098 connect(dlg, &WebEnginePartCertificateErrorDlg::finished, this, [this, dlg](int){ 0099 applyUserChoice(dlg);}); 0100 connect(dlg, &WebEnginePartCertificateErrorDlg::destroyed, this, &CertificateErrorDialogManager::removeDestroyedDialog); 0101 connect(window, &QWidget::destroyed, this, &CertificateErrorDialogManager::removeDestroyedWindow); 0102 m_dialogs.insert(window, dlg); 0103 dlg->open(); 0104 } 0105 0106 void CertificateErrorDialogManager::displayNextDialog(QWidget *window) 0107 { 0108 if (!window) { 0109 return; 0110 } 0111 auto findNext = [window](const CertificateErrorData &data) { 0112 return windowForPage(data.page) == window; 0113 }; 0114 auto it = std::find_if(m_certificates.begin(), m_certificates.end(), findNext); 0115 if (it == m_certificates.end()) { 0116 return; 0117 } 0118 displayDialog(*it, window); 0119 m_certificates.erase(it); 0120 } 0121 0122 void CertificateErrorDialogManager::applyUserChoice(WebEnginePartCertificateErrorDlg *dlg) 0123 { 0124 QWebEngineCertificateError error = dlg->certificateError(); 0125 WebEnginePartCertificateErrorDlg::UserChoice choice = dlg->userChoice(); 0126 if (choice == WebEnginePartCertificateErrorDlg::UserChoice::DontIgnoreError) { 0127 error.rejectCertificate(); 0128 } else { 0129 #if QT_VERSION_MAJOR < 6 0130 error.ignoreCertificateError(); 0131 #else 0132 error.acceptCertificate(); 0133 #endif 0134 if (choice == WebEnginePartCertificateErrorDlg::UserChoice::IgnoreErrorForever) { 0135 recordIgnoreForeverChoice(error); 0136 } 0137 } 0138 dlg->deleteLater(); 0139 } 0140 0141 void CertificateErrorDialogManager::removeDestroyedDialog(QObject *dlg) 0142 { 0143 auto findItemForDialog = [dlg](const std::pair<QObject*, QObject*>& pair){return pair.second == dlg;}; 0144 auto it = std::find_if(m_dialogs.constKeyValueBegin(), m_dialogs.constKeyValueEnd(), findItemForDialog); 0145 if (it == m_dialogs.constKeyValueEnd()) { 0146 return; 0147 } 0148 QWidget *window = qobject_cast<QWidget*>(it->first); 0149 m_dialogs.remove(it->first); 0150 if (window) { 0151 disconnect(window, nullptr, this, nullptr); 0152 displayNextDialog(window); 0153 } 0154 } 0155 0156 void CertificateErrorDialogManager::removeDestroyedWindow(QObject *window) 0157 { 0158 if (!window) { 0159 return; 0160 } 0161 m_dialogs.remove(window); 0162 } 0163 0164 void CertificateErrorDialogManager::recordIgnoreForeverChoice(const QWebEngineCertificateError& ce) 0165 { 0166 KConfigGroup grp(KSharedConfig::openConfig(), "CertificateExceptions"); 0167 QString url = ce.url().url(); 0168 #if QT_VERSION_MAJOR < 6 0169 int error = ce.error(); 0170 #else 0171 int error = ce.type(); 0172 #endif 0173 QList<int> exceptionsForUrl = grp.readEntry(url, QList<int>{}); 0174 exceptionsForUrl.append(error); 0175 grp.writeEntry(url, exceptionsForUrl); 0176 grp.sync(); 0177 } 0178 0179 0180