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 #ifndef WEBENGINEPART_CERTIFICATEERRORDIALOGMANAGER_H 0010 #define WEBENGINEPART_CERTIFICATEERRORDIALOGMANAGER_H 0011 0012 #include <QObject> 0013 #include <QWebEngineCertificateError> 0014 #include <QPointer> 0015 0016 class WebEnginePage; 0017 0018 namespace KonqWebEnginePart { 0019 0020 class WebEnginePartCertificateErrorDlg; 0021 0022 /** 0023 * @brief Class which takes care of queuing dialogs reporting certificate errors. 0024 * 0025 * Since calls to WebEnginePage::certificateError are made asynchronously, without 0026 * queuing it could happen that a second dialog is shown when there's another one 0027 * still visible. Since the dialogs are modal and they can cover each other, this can 0028 * cause issues for the user. To avoid this, this class ensures that only dialogs from 0029 * different windows can be shown at the same time. 0030 * 0031 * @internal The whole issue is caused by the use of @c QDialog::open instead of 0032 * @c QDialog::exec to display the dialog: since @c exec is synchronous, it will prevent 0033 * displaying a second dialog before the first has been closed. 0034 */ 0035 class CertificateErrorDialogManager : public QObject 0036 { 0037 Q_OBJECT 0038 0039 public: 0040 /** 0041 * @brief Constructor 0042 * 0043 * @param parent the parent object 0044 */ 0045 CertificateErrorDialogManager(QObject *parent=nullptr); 0046 0047 /** 0048 * @brief Destructor 0049 * 0050 */ 0051 ~CertificateErrorDialogManager(); 0052 0053 /** 0054 * @brief Displays a dialog regarding the certificate error or queues the certificate error 0055 * 0056 * If there's no currently displayed certificate error dialog for the window containing the page, 0057 * the dialog for the new certificate is immediately shown, otherwise the certificate error 0058 * is put in queue waiting to be displayed as soon as there aren't other dialogs for that 0059 * window. 0060 * 0061 * In all cases, the appropriate function is called on the certificate: @c ignoreCertificateError 0062 * or @c rejectCertificate if the dialog was displayed immediately or @c defer if it was queued. 0063 * @param _ce the certificate error 0064 * @param page the page which caused the certificate error 0065 * @return @b true if the certificate was overridable and @b false if it wasn't overridable. 0066 * @note In case the certificate wasn't overridable, @c rejectCertificate will be called on the 0067 * certificate. 0068 * @note In Qt6 the return value is ignored 0069 * @todo When removing compatibility with KF5, change the return value to `void` 0070 */ 0071 bool handleCertificateError(const QWebEngineCertificateError &_ce, WebEnginePage *page); 0072 0073 private: 0074 0075 /** 0076 * @brief Struct used to encapuslate information about certificate errors 0077 */ 0078 struct CertificateErrorData { 0079 /** 0080 * @brief The certificate error 0081 */ 0082 QWebEngineCertificateError error; 0083 /** 0084 * @brief The page which has caused the certificate error 0085 */ 0086 QPointer<WebEnginePage> page; 0087 }; 0088 0089 /** 0090 * @brief Whether the decision to always ignore the given error is recorded in the user settings 0091 * 0092 * @param ce the certificate error 0093 * @return @b true if the user has decided to always ignore the error and @b false otherwise 0094 */ 0095 static bool userAlreadyChoseToIgnoreError(const QWebEngineCertificateError &ce); 0096 0097 /** 0098 * @brief Records the user's choice to forever ignore the given error 0099 * 0100 * @param ce the error 0101 */ 0102 static void recordIgnoreForeverChoice(const QWebEngineCertificateError &ce); 0103 0104 /** 0105 * @brief The window (toplevel widget) associated to the given page 0106 * 0107 * @param page the page to retrieve the window for 0108 * @return the window associated with @p page or @b nullptr if either @p page or its @c view are @b nullptr 0109 */ 0110 static QWidget* windowForPage(WebEnginePage *page); 0111 0112 /** 0113 * @brief Displays a dialog for the given certificate error unless a certificate error dialog 0114 * for the same window is already visible. 0115 * 0116 * @param data the data describing the certificate error 0117 * @return @b true if the dialog was displayed and @b false if it wasn't 0118 * @note the dialog is displayed asynchronously 0119 */ 0120 bool displayDialogIfPossible(const CertificateErrorData &data); 0121 0122 /** 0123 * @brief Displays a dialog for the given certificate error 0124 * 0125 * The dialog is displayed asynchronously (using @c QDialog::open). The dialog result is used 0126 * in dialogClosed. 0127 * 0128 * @warning This function doesn't check whether a dialog for the given window 0129 * is already visible: it assumes that such check has been done by the caller. 0130 * @warning This function @b doesn't use windowForPage to determine which window the page belongs to: 0131 * it always uses @p window. 0132 * 0133 * @internal This function stores the new dialog and the corresponding window in #m_dialogs 0134 * 0135 * @param data the data describing the certificate error 0136 * @param window the window the dialog should be displayed in 0137 */ 0138 void displayDialog(const CertificateErrorData &data, QWidget *window); 0139 0140 0141 private slots: 0142 /** 0143 * @brief Removes a dialog from the list and displays the next dialog (if any) for the same window 0144 * 0145 * @param obj the dialog to remove. It is a @c QObject rather than a WebEnginePartCertificateErrorDlg 0146 * because this slot is called in response to the dialog @c destroyed signal, which has a @c QObject* as argument 0147 */ 0148 void removeDestroyedDialog(QObject *dlg); 0149 0150 /** 0151 * @brief Removes any dialog from the given window from the list 0152 * 0153 * @param obj the window. It is a @c QObject rather than a @c QWidget 0154 * because this slot is called in response to the window @c destroyed signal, which has a @c QObject* as argument 0155 */ 0156 void removeDestroyedWindow(QObject *window); 0157 0158 /** 0159 * @brief Applies the choice made by the user in the given dialog 0160 * 0161 * This function is called in response to the dialog's @b finished signal. 0162 * It calls @c ignoreCertificateError or @c rejectCertificate on the certificate error (retrieved using 0163 * WebEnginePartCertificateErrorDlg::certificateError) and, if the user chose to always ignore the error, 0164 * records the choice. 0165 * 0166 * This function also deletes the dialog (using @c deleteLater). 0167 * 0168 * @note This function @b doesn't display the next dialog for the associated window: that task is left to 0169 * removeDestroyedDialog, which is called in response to the dialog destruction. 0170 * 0171 * @param dlg the dialog 0172 */ 0173 void applyUserChoice(WebEnginePartCertificateErrorDlg *dlg); 0174 0175 /** 0176 * @brief Displays the certificate error dialog for the next error caused by a page associated with the given window 0177 * 0178 * If no such certificate error exists, nothing is done. 0179 * 0180 * @param window the window to display the next error for. 0181 */ 0182 void displayNextDialog(QWidget *window); 0183 0184 private: 0185 0186 /** 0187 * @brief A list of all the queued certificate errors together with the corresponding pages 0188 * 0189 * When a dialog for a certificate error is created, the corresponding entry is removed from the list 0190 * @internal The entry is removed when the dialog is created, not when it's destroyed 0191 * 0192 */ 0193 QVector<CertificateErrorData> m_certificates; 0194 0195 /** 0196 * @brief A hash associating each certificate error dialog with its window 0197 * 0198 * If the window is destroyed, the corresponding entry is removed from the list. 0199 * @note Keys and values are @c QObject* rather than more specific types because they're used 0200 * in slots connected with @c QObject::destroyed signals, whose argument is a @c QObject*. 0201 */ 0202 QHash<QObject*, QObject*> m_dialogs; 0203 0204 }; 0205 0206 } 0207 0208 #endif // WEBENGINEPART_CERTIFICATEERRORDIALOGMANAGER_H