summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2019-03-13 17:46:29 +0100
committerSimon Rettberg2019-03-13 17:46:29 +0100
commit2aec131158da9908dad0e56986f5366dd3de700e (patch)
treeb9d5d5efdf813a14f13f6a2f37e37109e93721f3
parentSet proper parent window for message box (diff)
downloadslxbrowser-2aec131158da9908dad0e56986f5366dd3de700e.tar.gz
slxbrowser-2aec131158da9908dad0e56986f5366dd3de700e.tar.xz
slxbrowser-2aec131158da9908dad0e56986f5366dd3de700e.zip
Add black/whitelisting of URLs
-rw-r--r--src/main.cpp55
-rw-r--r--src/slxbrowser.cpp149
-rw-r--r--src/slxbrowser.h18
3 files changed, 172 insertions, 50 deletions
diff --git a/src/main.cpp b/src/main.cpp
index b828d60..208a635 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -3,6 +3,7 @@
#include <QApplication>
#include <QKeyEvent>
#include <QCommandLineParser>
+#include <QTextStream>
class KeyHandler : public QObject
{
@@ -18,6 +19,8 @@ public:
}
};
+QStringList loadUrlList(const QString &file);
+
/**
* MAIN
*/
@@ -26,23 +29,61 @@ int main(int argc, char** argv)
QApplication app(argc, argv);
QCommandLineParser parser;
parser.addHelpOption();
- parser.addPositionalArgument("url", "URL to load");
- QCommandLineOption ignoreSsl("insecure", "Ignore SSL errors");
- QCommandLineOption fullscreen("fullscreen", "Run browser in full screen");
- QCommandLineOption reloadInterval("reload-interval", "Reload displayed page every X seconds", "seconds");
+ parser.addPositionalArgument("url", "URL to load.");
+ QCommandLineOption ignoreSsl("insecure", "Ignore SSL errors.");
+ QCommandLineOption fullscreen("fullscreen", "Run browser in full screen.");
+ QCommandLineOption reloadInterval("reload-interval", "Reload displayed page every X seconds.", "seconds");
+ QCommandLineOption whitelist("whitelist", "Path to a file of allowed URLs. Mutually exclusive with blacklist.", "file");
+ QCommandLineOption blacklist("blacklist", "Path to a file of disallowed URLs. Mutually exclusive with whitelist.", "file");
parser.addOption(ignoreSsl);
parser.addOption(fullscreen);
parser.addOption(reloadInterval);
+ parser.addOption(whitelist);
+ parser.addOption(blacklist);
parser.process(app);
QStringList list(parser.positionalArguments());
if (list.empty()) {
- QMessageBox::critical(NULL, "Error", "Need one argument: file name");
+ QMessageBox::critical(nullptr, "Error", "Need one argument: file name");
return 1;
}
- QString url(list[0]);
- SLXbrowser main(url, parser.isSet(fullscreen), parser.isSet(ignoreSsl), parser.value(reloadInterval).toInt());
+ if (parser.isSet(whitelist) && parser.isSet(blacklist)) {
+ QMessageBox::critical(nullptr, "Error", "Need either blacklist or whitelist, not both");
+ return 2;
+ }
+ BrowserSettings settings;
+ settings.url = list[0];
+ settings.fullscreen = parser.isSet(fullscreen);
+ settings.ignoreSslErrors = parser.isSet(ignoreSsl);
+ settings.reloadInterval = parser.value(reloadInterval).toInt();
+ if (parser.isSet(whitelist)) {
+ settings.urlList = loadUrlList(parser.value(whitelist));
+ } else if (parser.isSet(blacklist)) {
+ settings.urlList = loadUrlList(parser.value(blacklist));
+ }
+ settings.isWhitelist = parser.isSet(whitelist);
+ SLXbrowser main(settings);
main.show();
app.installEventFilter(new KeyHandler());
app.exec();
return 0;
}
+
+QStringList loadUrlList(const QString &file)
+{
+ QStringList stringList;
+ QFile textFile(file);
+ if (!textFile.open(QFile::ReadOnly)) {
+ QTextStream(stdout) << "Cannot open URL list\n";
+ return QStringList();
+ }
+ QTextStream textStream(&textFile);
+ while (true)
+ {
+ QString line = textStream.readLine();
+ if (line.isNull())
+ break;
+ else
+ stringList.append(line);
+ }
+ return stringList;
+}
diff --git a/src/slxbrowser.cpp b/src/slxbrowser.cpp
index 0690102..5ffe281 100644
--- a/src/slxbrowser.cpp
+++ b/src/slxbrowser.cpp
@@ -1,19 +1,24 @@
#include "slxbrowser.h"
#include "webview.h"
+#include "nam.h"
#include <QtWebKitWidgets>
#include <QWebPage>
#include <QNetworkReply>
#include <QSslConfiguration>
#include <QProgressBar>
+#include <QDateTime>
-SLXbrowser::SLXbrowser(QString url, bool fullscreen, bool ignoreSslErrors, int reloadIntervalSeconds)
+static QRegularExpression urlListToRegExp(const QStringList &list);
+
+SLXbrowser::SLXbrowser(BrowserSettings settings)
: QMainWindow(nullptr),
- _url(url),
- _ignoreSslErrors(ignoreSslErrors),
+ _settings(settings),
_unsupportedUri(false),
- _reloadIntervalMs(reloadIntervalSeconds * 1000)
+ _blockedSite(false),
+ _lastPageLoad(0)
{
- if (fullscreen) {
+ _settings.reloadInterval *= 1000;
+ if (_settings.fullscreen) {
this->showFullScreen();
this->setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
}
@@ -40,12 +45,21 @@ SLXbrowser::SLXbrowser(QString url, bool fullscreen, bool ignoreSslErrors, int r
connect(_browser, SIGNAL(loadProgress(int)), this, SLOT(loadProgress(int)));
//
QWebPage *page = _browser->page();
- QNetworkAccessManager *nam = new QNetworkAccessManager(this);
+ QNetworkAccessManager *nam;
+ if (_settings.urlList.isEmpty()) {
+ nam = new QNetworkAccessManager(this);
+ } else {
+ if (_settings.isWhitelist) {
+ // Just to be safe
+ _settings.urlList << _settings.url;
+ }
+ nam = new SlxNetworkAccessManager(urlListToRegExp(_settings.urlList), _settings.isWhitelist);
+ }
connect(nam, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)),
this, SLOT(sslErrors(QNetworkReply*, const QList<QSslError>&)));
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
page->setNetworkAccessManager(nam);
- page->mainFrame()->load(url);
+ page->mainFrame()->load(_settings.url);
//
_browser->show();
}
@@ -57,8 +71,8 @@ SLXbrowser::~SLXbrowser()
void SLXbrowser::loadStarted()
{
_reset.stop();
- if (_reloadIntervalMs > 0) {
- _reset.start(_reloadIntervalMs + 10000);
+ if (_settings.reloadInterval > 0) {
+ _reset.start(_settings.reloadInterval + 10000);
}
_normalError.clear();
_sslErrors.clear();
@@ -69,37 +83,63 @@ void SLXbrowser::loadStarted()
void SLXbrowser::loadFinished(bool ok)
{
_progress->hide();
- if (!_browser->wasAbortedDownload() && !_unsupportedUri && !ok) {
- _browser->page()->mainFrame()->setHtml("<html><body style='background:blue;color:white'><br><br><center><h1>Page Load Error</h1><pre id='content'></pre></body></html>");
- QWebElement el = _browser->page()->mainFrame()->documentElement().findFirst("#content");
- QString str;
- if (!_sslErrors.empty()) {
- str.append("SSL Errors:\n");
- for (QSslError err : _sslErrors) {
- str.append(err.errorString());
- str.append('\n');
+ qint64 now = QDateTime::currentMSecsSinceEpoch();
+ if (!_browser->wasAbortedDownload() && !ok) {
+
+ if (_unsupportedUri) {
+ QMessageBox::warning(this, QString::fromUtf8("Denied"),
+ QString::fromUtf8("This URL type is not supported.\n\n"
+ "Diese Art Link wird nicht unterstützt.\n\n"
+ "(z.B. Mail)"));
+ } else if (_blockedSite) {
+ int numElems = _browser->page()->mainFrame()->documentElement().findAll("*").count();
+ if (now - _lastPageLoad < 500 && numElems < 15) {
+ // Was probably a JS redirect, go back before displaying the error
+ _browser->page()->triggerAction(QWebPage::Back);
}
- } else if (_normalError.length() != 0) {
- str.append("Load Error:\n");
- str.append(_normalError);
+ QTimer::singleShot(5, [=]() {
+ QMessageBox::warning(this, QString::fromUtf8("Denied"),
+ QString::fromUtf8("Target URL not allowed.\n\n"
+ "Dieser Link führt auf eine nicht erlaubte Seite."));
+ });
+ /*
+ _browser->page()->mainFrame()->setHtml("<html><body style='background:white;color:black'><br><br>"
+ "<center><h1>Zugriff verweigert</h1>"
+ "<p>Diese URL wurde gefiltert.<br>"
+ "<a href='javascript:window.history.back()'>Zurück</a></p></center>"
+ "</body></html>");
+ */
} else {
- str.append("Unknown Error");
+ _browser->page()->mainFrame()->setHtml("<html><body style='background:blue;color:white'><br><br>"
+ "<center><h1>Page Load Error</h1><pre id='content'></pre></center>"
+ "</body></html>");
+ QWebElement el = _browser->page()->mainFrame()->documentElement().findFirst("#content");
+ QString str;
+ if (!_sslErrors.empty()) {
+ str.append("SSL Errors:\n");
+ for (QSslError err : _sslErrors) {
+ str.append(err.errorString());
+ str.append('\n');
+ }
+ } else if (_normalError.length() != 0) {
+ str.append("Load Error:\n");
+ str.append(_normalError);
+ } else {
+ str.append("Unknown Error");
+ }
+ str.append("\n\n\n\n" + QDateTime::currentDateTime().toString());
+ el.setPlainText(str);
}
- str.append("\n\n\n\n" + QDateTime::currentDateTime().toString());
- el.setPlainText(str);
_sslErrors.clear();
_normalError.clear();
- _reset.start(30000);
- } else if (_reloadIntervalMs > 0) {
- _reset.start(_reloadIntervalMs);
+ _reset.start(qMin(30000, _settings.reloadInterval > 0 ? _settings.reloadInterval : 30000));
+ } else if (_settings.reloadInterval > 0) {
+ _reset.start(_settings.reloadInterval);
}
- if (_unsupportedUri && !ok) {
- QMessageBox::warning(this, QString::fromUtf8("Denied"),
- QString::fromUtf8("This URL type is not supported.\n\n"
- "Diese Art Link wird nicht unterstützt.\n\n"
- "(z.B. Mail)"));
- }
+
_unsupportedUri = false;
+ _blockedSite = false;
+ _lastPageLoad = now;
}
void SLXbrowser::loadProgress(int progress)
@@ -109,7 +149,7 @@ void SLXbrowser::loadProgress(int progress)
void SLXbrowser::sslErrors(QNetworkReply* reply, const QList<QSslError>& errors)
{
- if (_ignoreSslErrors) {
+ if (_settings.ignoreSslErrors) {
reply->ignoreSslErrors();
return;
}
@@ -118,17 +158,48 @@ void SLXbrowser::sslErrors(QNetworkReply* reply, const QList<QSslError>& errors)
void SLXbrowser::requestFinished(QNetworkReply *reply)
{
- if (reply->error() == QNetworkReply::NoError) {
- _unsupportedUri = false;
- } else if (reply->error() == QNetworkReply::ProtocolUnknownError) {
+ if (reply->error() == QNetworkReply::ProtocolUnknownError) {
_unsupportedUri = true;
+ } else if (reply->error() == QNetworkReply::UnknownNetworkError) {
+ _blockedSite = true;
} else {
- qDebug() << reply->error();
+ //qDebug() << reply->error();
_normalError = reply->errorString();
}
}
void SLXbrowser::reloadInitial()
{
- _browser->page()->mainFrame()->load(_url);
+ _browser->page()->mainFrame()->load(_settings.url);
+}
+
+static QRegularExpression urlListToRegExp(const QStringList &list)
+{
+ // We search in the escaped string, so actually look for \*\* and \*
+ // Capture char before that because it must not be another backslash, as that
+ // means the star was already escaped in the list.
+ // Since these are C strings there are some additional backslashes here.
+ static const QRegularExpression STARSTAR("(^|[^\\\\])\\\\\\*\\\\\\*");
+ static const QRegularExpression STAR("(^|[^\\\\])\\\\\\*");
+ static const QRegularExpression QUEST("(^|[^\\\\])\\\\\\?");
+ static const QString STARSTAR_REP("\\1.*");
+ static const QString STAR_REP("\\1[^/]*");
+ static const QString QUEST_REP("\\1.?");
+ QStringList regexes; // All my regex's live in Regtexas
+ for (const QString &str : list) {
+ QString mangled;
+ if (str.contains(QLatin1String("//"))) {
+ mangled = str;
+ } else if (str.contains(QLatin1Char('/')) || str.contains(QLatin1String("**"))) {
+ mangled = "*//" + str;
+ } else {
+ mangled = "*//" + str + "/**";
+ }
+ mangled = QRegularExpression::escape(mangled);
+ mangled = mangled.replace(STARSTAR, STARSTAR_REP).replace(STAR, STAR_REP)
+ .replace(QUEST, QUEST_REP);
+ regexes << mangled;
+ }
+ qDebug() << regexes;
+ return QRegularExpression("^(" + regexes.join('|') + ")$");
}
diff --git a/src/slxbrowser.h b/src/slxbrowser.h
index c036821..f68e186 100644
--- a/src/slxbrowser.h
+++ b/src/slxbrowser.h
@@ -11,11 +11,21 @@ class WebView;
class QProgressBar;
class QNetworkReply;
+struct BrowserSettings
+{
+ QString url;
+ bool fullscreen;
+ bool ignoreSslErrors;
+ int reloadInterval;
+ bool isWhitelist;
+ QStringList urlList;
+};
+
class SLXbrowser : public QMainWindow
{
Q_OBJECT
public:
- SLXbrowser(QString url, bool fullscreen, bool ignoreSslErrors, int reloadInterval);
+ SLXbrowser(BrowserSettings settings);
virtual ~SLXbrowser();
private slots:
@@ -27,15 +37,15 @@ private slots:
void reloadInitial();
private:
- QString _url;
- bool _ignoreSslErrors;
+ BrowserSettings _settings;
bool _unsupportedUri;
+ bool _blockedSite;
WebView *_browser;
QProgressBar *_progress;
QTimer _reset;
QList<QSslError> _sslErrors;
QString _normalError;
- int _reloadIntervalMs;
+ qint64 _lastPageLoad;
};
#endif /* SLXBROWSER_H_ */