File indexing completed on 2024-05-19 05:01:23

0001 /*
0002     This file is part of the KDE project.
0003 
0004     SPDX-FileCopyrightText: 2009 Dawit Alemayehu <adawit@kde.org>
0005     SPDX-FileCopyrightText: 2018 Stefano Crocco <stefano.crocco@alice.it>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 #ifndef WEBENGINEWALLET_H
0010 #define WEBENGINEWALLET_H
0011 
0012 #include <QObject>
0013 #include <QString>
0014 #include <QList>
0015 #include <QPair>
0016 #include <QUrl>
0017 #include <QWidget>
0018 #include <QtGlobal>
0019 #include <QDebug>
0020 #include <QWebEnginePage>
0021 #include <QMap>
0022 
0023 #include "settings/webenginesettings.h"
0024 
0025 class WebEnginePage;
0026 class WebEnginePart;
0027 class QWebEngineScript;
0028 
0029 /**
0030  * @brief Class which allows WebEnginePart to cache form data in `KWallet`
0031  *
0032  */
0033 class WebEngineWallet : public QObject
0034 {
0035     Q_OBJECT
0036 
0037 public:
0038 
0039     /**
0040      * Holds data from a HTML &lt;form&gt; element.
0041      */
0042     struct WebForm {
0043 
0044         /**
0045          * @brief Enum describing a field type
0046          */
0047         enum class WebFieldType {
0048             Text, ///< The field has type @e text
0049             Password, ///< The field has type @e password
0050             Email, ///< The field has type @e email
0051             Other ///< The field has a type not described by other values
0052         };
0053 
0054         /**
0055          * @brief The WebFieldType corresponding to a given field type name
0056          *
0057          * @param name the name of the field type. It must be lowercase
0058          * @return The WebForm::WebFieldType value corresponding to @p name. If @p name is not @e text, @e password or @e email, WebFieldType::Other is returned
0059          * @note For efficiency, this function requires @p name to be lowercase
0060          */
0061         static WebFieldType fieldTypeFromTypeName(const QString &name);
0062 
0063         /**
0064          * @brief A string representation of the type of a web field
0065          *
0066          * @param type the type of the field
0067          * @param localized whether or not the returned type should be localized
0068          * @return a string with the name of the type @type. If @p localized is @b true, `i18n` will be used to localize the string
0069          */
0070         static QString fieldNameFromType(WebFieldType type, bool localized = false);
0071 
0072         /**
0073          * @brief Struct describing a field inside of a web form
0074          */
0075         struct WebField {
0076             QString name; ///< The name of the field
0077             QString id; ///< The id of the field
0078             WebFieldType type; ///< The type of the field
0079             bool readOnly; ///< Whether the field is read-only
0080             bool disabled; ///< Whether the field is disabled
0081             bool autocompleteAllowed; ///< Whether the autocomplete attribute of the field is on or off
0082             QString value; ///< The value of the field
0083             QString label; ///< The HTML label associated with the field
0084 
0085         /**
0086          * @brief Whether the field can be automatically filled or not
0087          *
0088          * A field can be automatically filled if all these conditions are true:
0089          * - it is @b not read-only
0090          * - it is @b not disabled
0091          * - autocomplete is @b on
0092          *
0093          * @return @b true if the field can be automatically filled and @b false otherwise
0094          * @note The user can request that a field is cached (and so filled) even if this function returns false
0095          */
0096             bool isAutoFillable() const {return !readOnly && !disabled && autocompleteAllowed;}
0097         };
0098 
0099         /**
0100          * @brief Removes all fields which aren't automatically fillable from the forms
0101          *
0102          * After calling this function, \link fields \endlink will only contain fields for which WebField::isAutoFillable() returns @b true.
0103          * If none of the fields is automatically fillable, #fields will be empty.
0104          */
0105         void deleteNotAutoFillableFields();
0106 
0107         /**
0108          * @brief Returns a copy of this object which only contains auto fillable fields
0109          *
0110          * @return a copy of this object which only contains fields for which WebField::isAutoFillable() returns @b true
0111          */
0112         WebForm withAutoFillableFieldsOnly() const;
0113 
0114         /**
0115          * @brief Whether the form contains fields of type @e password
0116          *
0117          * @return @b true if at least one of the #fields has type @e password and @b false otherwise
0118          */
0119         bool hasPasswords() const;
0120 
0121         /**
0122          * @brief Whether the form has autofillable fields
0123          *
0124          * @return @b true if at least one of the #fields can be automatically filled according to WebField::isAutoFillable() and @b false otherwise
0125          */
0126         bool hasAutoFillableFields() const;
0127 
0128         /**
0129          * @brief Whether any of the writable fields in the form have non-empty values
0130          *
0131          * @return @b true if at least one of the #fields is not read-only and has a non-empty value
0132          */
0133         bool hasFieldsWithWrittenValues() const;
0134 
0135         /**
0136          * @brief Creates a WebEngineSettings::WebFormInfo from this object
0137          *
0138          * @return a WebEngineSettings::WebFormInfo having the same name, frame path and fields names as this object
0139          */
0140         WebEngineSettings::WebFormInfo toSettingsInfo() const;
0141 
0142         /// @brief The URL the form was found at.
0143         QUrl url;
0144 
0145         ///@brief The name attribute of the form.
0146         QString name;
0147 
0148         /// @brief The position of the form on the web page, relative to other forms.
0149         QString index;
0150 
0151         /** @brief The path of the frame the form belongs to relative to the toplevel window (in the javascript sense).
0152          *
0153          * This is stored as a string containing a javascript array (it is passed as is to javascript code, so no need to store it in C++ format
0154          */
0155         QString framePath;
0156 
0157         /// @brief The name and value attributes of each input element in the form.
0158         QVector<WebField> fields;
0159     };
0160 
0161     /**
0162      * @brief A list of web forms
0163      */
0164     typedef QVector<WebForm> WebFormList;
0165 
0166     /**
0167      * @brief Constructs a WebEngineWebWallet
0168      *
0169      * @p parent is usually the WebEnginePage this wallet is being used for.
0170      *
0171      * The @p wid parameter is used to tell the KWallet manager which window
0172      * is requesting access to the wallet.
0173      *
0174      * @param parent  the owner of this wallet
0175      * @param wid     the window ID of the window the web page will be
0176      *                embedded in
0177      */
0178     explicit WebEngineWallet(WebEnginePart *parent = nullptr, WId wid = 0);
0179 
0180     /**
0181      * @brief Destructor
0182      */
0183     ~WebEngineWallet() override;
0184 
0185     /**
0186      * @brief Whether the wallet is open or not
0187      * @return @b true if the wallet is open and @b false otherwise
0188      */
0189     bool isOpen() const;
0190 
0191     /**
0192      * @brief Attempts to save the form data from @p page and its children frames.
0193      *
0194      * You must connect to the @ref saveFormDataRequested signal and call either
0195      * @ref rejectSaveFormDataRequest or @ref acceptSaveFormDataRequest signals
0196      * in order to complete the save request. Otherwise, you request will simply
0197      * be ignored.
0198      *
0199      * Note that this function is asynchronous, as it requires running javascript code
0200      * on the page using QWebEnginePage::runJavaScript. This function only requests
0201      * for the form data to be saved when QWebEnginePage::runJavaScript finishes.
0202      */
0203     void saveFormData(WebEnginePage *page, const WebFormList &allForms, bool force = false);
0204 
0205     /**
0206      * @brief Attempts to fill forms contained in @p page with cached data.
0207      *
0208      * Note that this function is asynchronous, as it requires running javascript code
0209      * on the page using QWebEnginePage::runJavaScript. This function only requests
0210      * for the form data to be filled when QWebEnginePage::runJavaScript finishes.
0211      */
0212     void fillFormData(WebEnginePage *page, const WebFormList &allForms);
0213 
0214     /**
0215      * @brief Removes the form data specified by @p forms from the persistent storage.
0216      *
0217      * Note that this function will remove all cached data for forms found in @p page.
0218      *
0219      * Note that this function is asynchronous, as it requires running javascript code
0220      * on the page using QWebEnginePage::runJavaScript. This function only requests
0221      * for the form data to be removed when QWebEnginePage::runJavaScript finishes.
0222      */
0223     void removeFormData(WebEnginePage *page);
0224 
0225     /**
0226      * @brief Removes the form data specified by @p forms from the persistent storage.
0227      *
0228      * @param forms The forms to remove
0229      * @see formsWithCachedData
0230      */
0231     void removeFormData(const WebFormList &forms);
0232     
0233     /**
0234      * @brief the forms to save for the given key
0235      *
0236      * @param key the key associated with the page whose forms should be returned. It's the same key passed by the saveFormDataRequested() signal
0237      * @return the forms associated with the page corresponding to the given key
0238      */
0239     WebFormList pendingSaveData(const QString &key);
0240 
0241     /**
0242      * @brief Whether the user has customized which forms should be cached for the given URL
0243      *
0244      * @param url the URL to check
0245      * @return @b true if the user has customized the forms to cache for @p URL and false if the forms to cache for @p URL are detected automatically
0246      */
0247     static bool hasCustomizedCacheableForms(const QUrl &url);
0248 
0249 public Q_SLOTS:
0250     /**
0251      * @brief Accepts the save form data request associated with @p key.
0252      *
0253      * The @p key parameter is the one sent through the @ref saveFormDataRequested
0254      * signal.
0255      *
0256      * You must always call this function or @ref rejectSaveFormDataRequest in
0257      * order to complete the save form data request. Otherwise, the request will
0258      * simply be ignored.
0259      *
0260      * @see saveFormDataRequested.
0261      */
0262     void acceptSaveFormDataRequest(const QString &key);
0263 
0264     /**
0265      * @brief Rejects the save form data request associated with @p key.
0266      *
0267      * The @p key parameter is the one sent through the @ref saveFormDataRequested
0268      * signal.
0269      *
0270      * @see saveFormDataRequested.
0271      */
0272     void rejectSaveFormDataRequest(const QString &key);
0273 
0274     /**
0275      * @brief Detects the form in the given WebEnginePage and fills its form with cached data
0276      *
0277      * It usually is called in response to the <a href="https://doc.qt.io/qt-5/qwebenginepage.html#loadFinished">WebEnginePage::loadFinished</a> signal.
0278      *
0279      * @param page the WebEnginePage whose forms should be filled
0280      */
0281     void detectAndFillPageForms(WebEnginePage *page);
0282 
0283     /**
0284      * @brief Caches the contents of the fields
0285      *
0286      * @param page the page whose forms should be saved. If @b nullptr, nothing is done
0287      */
0288     void saveFormsInPage(WebEnginePage *page);
0289 
0290     /**
0291      * @brief Displays a dialog where the user can choose which fields in the current page should be cached
0292      *
0293      * If the user asks for it, besides saving the choice of fields, this function also immediately stores the field contents in the cache.
0294      * @note If the fields contents are cached immediately, the old cached contents is overwritten without confirmation.
0295      *
0296      * @param page the page for which to choose the forms to cache
0297      * @param widget the widget to use as the dialog parent
0298      */
0299     void customizeFieldsToCache(WebEnginePage *page, QWidget *widget = nullptr);
0300 
0301     /**
0302      * @brief Remove the customized list of forms to cache for a given URL
0303      *
0304      * @param url the URL of the page whose customization should be removed
0305      * @note This function doesn't remove the cached information but only the list of which forms should be cached for the given URL
0306      */
0307     void removeCustomizationForPage(const QUrl &url);
0308 
0309     /**
0310      * @brief Immediately caches the form data of the given page
0311      *
0312      * @param page the page whose form data should be cached
0313      */
0314     void savePageDataNow(WebEnginePage *page);
0315 
0316 Q_SIGNALS:
0317     /**
0318      * @brief This signal is emitted whenever a save form data request is received.
0319      *
0320      * Unless you connect to this signal and call @ref acceptSaveFormDataRequest
0321      * or @ref rejectSaveFormDataRequest slots, the save form data requested through
0322      * @ref saveFormData will simply be ignored.
0323      *
0324      * @p key is a value that uniquely identifies the save request and @p url
0325      * is the address for which the form data is being saved.
0326      *
0327      * @see acceptSaveFormDataRequest
0328      * @see rejectSaveFormDataRequest
0329      */
0330     void saveFormDataRequested(const QString &key, const QUrl &url);
0331 
0332     /**
0333      * @brief This signal is emitted whenever a save form data request is completed.
0334      *
0335      * @p ok will be set to true if the save form data request for @p url was
0336      * completed successfully.
0337      *
0338      * @see saveFormDataRequested
0339      */
0340     void saveFormDataCompleted(const QUrl &url, bool ok);
0341 
0342     /**
0343      * @brief This signal is emitted whenever a fill form data request is completed.
0344      *
0345      * @p ok will be set to true if any forms were successfully filled with
0346      * cached data from the persistent storage.
0347      *
0348      * @see fillFormData
0349      * @since 4.5
0350      */
0351     void fillFormRequestCompleted(bool ok);
0352 
0353     /**
0354      * @brief Signal emitted from detectAndFillPageForms() after form detection has finished.
0355      *
0356      * @param url the URL of the page
0357      * @param found whether the page contains any form of type @e text, @e, email or @e password
0358      * @param autoFillableFound whether the page contains any form which can be automatically filled
0359      *
0360      * @see detectAndFillPageForms()
0361      * @see WebForm::WebField::isAutoFillable()
0362      */
0363     void formDetectionDone(const QUrl& url, bool found, bool autoFillableFound);
0364 
0365     /**
0366      * @brief This signal is emitted whenever the current wallet is closed.
0367      */
0368     void walletClosed();
0369 
0370     /**
0371      * @brief Signal emitted when the wallet is opened
0372      */
0373     void walletOpened();
0374 
0375 protected:
0376     /**
0377      * @brief Returns a list of forms for @p url that are waiting to be filled.
0378      *
0379      * This function returns an empty list if there is no pending requests
0380      * for filling forms associated with @p url.
0381      *
0382      * @return a list of forms for @p url that are waiting to be filled.
0383      */
0384     WebFormList formsToFill(const QUrl &url) const;
0385 
0386     /**
0387      * @brief Returns forms to be removed from persistent storage.
0388      *
0389      * @return a list of forms to be removed from persistent storage.
0390      */
0391     WebFormList formsToDelete() const;
0392 
0393     /**
0394      * The key under which the custom list of fields to cache for a page should be saved
0395      *
0396      * @param url the URL of the page
0397      * @see WebEngineSettings::setCustomizedCacheableFieldsForPage()
0398      */
0399     static QString customFormsKey(const QUrl &url);
0400 
0401     /**
0402      * @brief Whether or not there's data associate with @p form in the persistent storage
0403      *
0404      * @return @b true when there is data associated with @p form in the
0405      * persistent storage and @b false otherwise.
0406      */
0407     bool hasCachedFormData(const WebForm &form) const;
0408 
0409     /**
0410      * @return Fills the web forms in frame that point to @p url with data from @p forms.
0411      *
0412      * @param url the URL of the page
0413      * @param forms the forms to fill the page with
0414      * @see fillFormDataFromCache.
0415      */
0416     void fillWebForm(const QUrl &url, const WebFormList &forms);
0417 
0418     /**
0419      * @brief Fills form data from persistent storage.
0420      *
0421      * If you reimplement this function, call @ref formsToFill to obtain
0422      * the list of forms pending to be filled. Once you fill the list with
0423      * the cached data from the persistent storage, you must call @p fillWebForm
0424      * to fill out the actual web forms.
0425      *
0426      * @see formsToFill
0427      * @param list the list of URLs to fill
0428      */
0429     void fillFormDataFromCache(const QList<QUrl> &list);
0430 
0431     /**
0432      * @brief Stores form data associated with @p key to a persistent storage.
0433      *
0434      * If you reimplement this function, call @ref formsToSave to obtain the
0435      * list of form data pending to be saved to persistent storage.
0436      *
0437      * @param key the string to retrieve the data
0438      * @see formsToSave
0439      */
0440     void saveFormDataToCache(const QString &key);
0441 
0442     /**
0443      * @brief Removes all cached form data associated with @p forms from persistent storage.
0444      *
0445      * If you reimplement this function, call @ref formsToDelete to obtain the
0446      * list of form data pending to be removed from persistent storage.
0447      *
0448      * @param forms the forms to delete
0449      * @see formsToDelete
0450      */
0451     void removeFormDataFromCache(const WebFormList &forms);
0452 
0453     /**
0454      * @brief Enum to distinguish between filling and saving operations with forms
0455      */
0456     enum class CacheOperation {
0457         Fill, ///< Forms are being filled
0458         Save ///< Forms are being cached
0459     };
0460 
0461     /**
0462      * @brief Selects from the given list of forms for an URL the fields to cache
0463      *
0464      * Depending on the user choices, this function can return either the result of calling WebForm::withAutoFillableFieldsOnly() on each form
0465      * or the customized fields list chosen by the user.
0466      *
0467      * @param url the URL of the page
0468      * @param allForms the list of all forms contained in the page
0469      * @param op whether the function should return the forms to fill or those to save
0470      * @return a list of all cacheable forms in the page according to the user's settings
0471      */
0472     WebFormList cacheableForms(const QUrl &url, const WebFormList &allForms, CacheOperation op) const;
0473 
0474 private:
0475     class WebEngineWalletPrivate;
0476     friend class WebEngineWalletPrivate;
0477     WebEngineWalletPrivate *const d;
0478 
0479     Q_PRIVATE_SLOT(d, void _k_openWalletDone(bool))
0480     Q_PRIVATE_SLOT(d, void _k_walletClosed())
0481 };
0482 
0483 QDebug operator<<(QDebug dbg, const WebEngineWallet::WebForm form);
0484 QDebug operator<<(QDebug dbg, const WebEngineWallet::WebForm::WebFieldType type);
0485 QDebug operator<<(QDebug dbg, const WebEngineWallet::WebForm::WebField field);
0486 
0487 #endif // WEBENGINEWALLET_H