aboutsummaryrefslogtreecommitdiff
path: root/src/webengine/webpage.cpp
blob: ecbb1b992c5b3bc09114bdab2c4451c9615fd013 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * This file is part of smolbote. It's copyrighted by the contributors recorded
 * in the version control history of the file, available from its original
 * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
 *
 * SPDX-License-Identifier: GPL-3.0
 */

#include "webpage.h"
#include <QLayout>
#include <QMessageBox>
#include <QTimer>
#include <QWebEngineFullScreenRequest>
#include <QWebEngineCertificateError>

QString tr_terminationStatus(QWebEnginePage::RenderProcessTerminationStatus status)
{
    switch(status) {
    case QWebEnginePage::NormalTerminationStatus:
        return QObject::tr("The render process terminated normally.");
    case QWebEnginePage::AbnormalTerminationStatus:
        return QObject::tr("The render process terminated with with a non-zero exit status.");
    case QWebEnginePage::CrashedTerminationStatus:
        return QObject::tr("The render process crashed, for example because of a segmentation fault.");
    case QWebEnginePage::KilledTerminationStatus:
        return QObject::tr("The render process was killed, for example by SIGKILL or task manager kill.");
    }

    return QObject::tr("The render process was terminated with an unknown status.");
}

QString feature_toString(QWebEnginePage::Feature feature)
{
    switch(feature) {
    case QWebEnginePage::Notifications:
        return QObject::tr("Notifications");
    case QWebEnginePage::Geolocation:
        return QObject::tr("Geolocation");
    case QWebEnginePage::MediaAudioCapture:
        return QObject::tr("Audio Capture");
    case QWebEnginePage::MediaVideoCapture:
        return QObject::tr("Video Capture");
    case QWebEnginePage::MediaAudioVideoCapture:
        return QObject::tr("Audio and Video Capture");
    case QWebEnginePage::MouseLock:
        return QObject::tr("Mouse Lock");
    case QWebEnginePage::DesktopVideoCapture:
        return QObject::tr("Desktop Video Capture");
    case QWebEnginePage::DesktopAudioVideoCapture:
        return QObject::tr("Desktop Audio and Video Capture");
    }

    return QObject::tr("Unknown feature");
}

WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
    : QWebEnginePage(profile, parent)
{
    connect(this, &WebPage::fullScreenRequested, this, [](QWebEngineFullScreenRequest request) {
        request.accept();
    });

    connect(this, &QWebEnginePage::featurePermissionRequested, this, &WebPage::featurePermissionDialog);
    connect(this, &QWebEnginePage::renderProcessTerminated, this, &WebPage::renderProcessCrashed);
}

bool WebPage::certificateError(const QWebEngineCertificateError &certificateError)
{
    QMessageBox messageBox;

    messageBox.setWindowTitle(tr("SSL Error"));
    if(certificateError.isOverridable())
        messageBox.setIcon(QMessageBox::Warning);
    else
        messageBox.setIcon(QMessageBox::Critical);

    messageBox.setText(tr("An SSL error has occurred on <strong>%1</strong>").arg(certificateError.url().toString()));
    messageBox.setInformativeText(tr("<p>%1</p>"
                                     "<p>This error %2 be overridden.</p>")
                                      .arg(certificateError.errorDescription(),
                                          certificateError.isOverridable() ? tr("can") : tr("cannot")));
    messageBox.setDetailedText(tr("Error code: %1").arg(certificateError.error()));

    if(certificateError.isOverridable()) {
        messageBox.setStandardButtons(QMessageBox::Ignore | QMessageBox::Abort);
        messageBox.setDefaultButton(QMessageBox::Ignore);
    } else
        messageBox.setStandardButtons(QMessageBox::Abort);

    auto resp = messageBox.exec();

    return resp == QMessageBox::Ignore;
}

void WebPage::featurePermissionDialog(const QUrl &securityOrigin, QWebEnginePage::Feature feature)
{
    QMessageBox messageBox;

    messageBox.setWindowTitle(tr("Feature permission request"));
    messageBox.setIcon(QMessageBox::Question);
    messageBox.setText(tr("<p>The webpage <strong>%1</strong> has requested permission to access: %2</p>"
                          "<p>Allow this feature?</p>")
                           .arg(securityOrigin.toString(), feature_toString(feature)));

    messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    messageBox.setDefaultButton(QMessageBox::No);

    if(messageBox.exec() == QMessageBox::Yes)
        setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser);
    else
        setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionDeniedByUser);
}

void WebPage::renderProcessCrashed(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode)
{
    if(terminationStatus != QWebEnginePage::NormalTerminationStatus) {
#ifdef QT_DEBUG
        qDebug("render process terminated: [%i] %i", terminationStatus, exitCode);
#endif

        QString page = "<html><body><h1>This tab has crashed!</h1>%message%</body></html>";
        page.replace(QLatin1String("%message%"), QString("<p>%1<br>Exit code is %2.</p>"
                                                         "<p>Press <a href='%3'>here</a> to reload this tab.</p>")
                                                     .arg(tr_terminationStatus(terminationStatus), QString::number(exitCode), this->url().toEncoded()));

        QTimer::singleShot(0, this, [=]() {
            setHtml(page.toUtf8(), url());
        });
    }
}